summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore4
-rwxr-xr-xBUILD/compile-pentium-gcov15
-rwxr-xr-xBUILD/compile-pentium6413
-rwxr-xr-xBUILD/compile-pentium64-debug2
-rwxr-xr-xBUILD/compile-pentium64-debug-max2
-rwxr-xr-xBitKeeper/triggers/pre-outgoing.crash-protect.pl85
-rwxr-xr-xBitKeeper/triggers/pre-resolve.crash-protect.pl85
-rw-r--r--client/Makefile.am10
-rw-r--r--client/client_priv.h.rej15
-rw-r--r--client/get_password.c4
-rw-r--r--client/mysql.cc1
-rw-r--r--client/mysqlbinlog.cc17
-rw-r--r--client/mysqldump.c63
-rw-r--r--client/mysqltest.c3
-rw-r--r--config/ac-macros/misc.m497
-rw-r--r--config/ac-macros/ssl.m410
-rw-r--r--configure.in139
-rw-r--r--extra/yassl/CMakeLists.txt2
-rw-r--r--extra/yassl/examples/echoserver/echoserver.cpp3
-rw-r--r--extra/yassl/include/openssl/crypto.h4
-rwxr-xr-xextra/yassl/include/openssl/generate_prefix_files.pl45
-rw-r--r--extra/yassl/include/openssl/prefix_crypto.h1
-rw-r--r--extra/yassl/include/openssl/prefix_ssl.h152
-rw-r--r--extra/yassl/include/openssl/ssl.h13
-rw-r--r--extra/yassl/include/socket_wrapper.hpp6
-rw-r--r--extra/yassl/include/yassl_error.hpp4
-rw-r--r--extra/yassl/include/yassl_int.hpp19
-rw-r--r--extra/yassl/src/Makefile.am2
-rw-r--r--extra/yassl/src/handshake.cpp15
-rw-r--r--extra/yassl/src/socket_wrapper.cpp18
-rw-r--r--extra/yassl/src/ssl.cpp45
-rw-r--r--extra/yassl/src/template_instnt.cpp2
-rw-r--r--extra/yassl/src/timer.cpp12
-rw-r--r--extra/yassl/src/yassl_error.cpp9
-rw-r--r--extra/yassl/src/yassl_int.cpp55
-rw-r--r--extra/yassl/taocrypt/CMakeLists.txt2
-rw-r--r--extra/yassl/taocrypt/include/block.hpp2
-rw-r--r--extra/yassl/taocrypt/include/md4.hpp65
-rw-r--r--extra/yassl/taocrypt/include/runtime.hpp4
-rw-r--r--extra/yassl/taocrypt/src/Makefile.am2
-rw-r--r--extra/yassl/taocrypt/src/integer.cpp5
-rw-r--r--extra/yassl/taocrypt/src/md4.cpp154
-rw-r--r--extra/yassl/taocrypt/src/misc.cpp13
-rw-r--r--extra/yassl/taocrypt/src/template_instnt.cpp2
-rw-r--r--extra/yassl/taocrypt/taocrypt.dsp8
-rwxr-xr-xextra/yassl/taocrypt/taocrypt.vcproj24
-rw-r--r--extra/yassl/taocrypt/test/test.cpp53
-rw-r--r--extra/yassl/testsuite/Makefile.am2
-rw-r--r--extra/yassl/testsuite/test.hpp8
-rwxr-xr-xextra/yassl/yassl.vcproj4
-rw-r--r--include/Makefile.am3
-rw-r--r--include/atomic/nolock.h169
-rw-r--r--include/atomic/rwlock.h161
-rw-r--r--include/atomic/x86-gcc.h59
-rw-r--r--include/atomic/x86-msvc.h85
-rw-r--r--include/base64.h2
-rw-r--r--include/config-win.h3
-rw-r--r--include/heap.h3
-rw-r--r--include/m_string.h24
-rw-r--r--include/my_atomic.h46
-rw-r--r--include/my_base.h14
-rw-r--r--include/my_bitmap.h53
-rw-r--r--include/my_global.h51
-rw-r--r--include/my_net.h4
-rw-r--r--include/my_nosys.h3
-rw-r--r--include/my_pthread.h6
-rw-r--r--include/my_sys.h25
-rw-r--r--include/my_tree.h8
-rw-r--r--include/myisam.h1
-rw-r--r--include/myisammrg.h1
-rw-r--r--include/mysql/plugin.h71
-rw-r--r--include/mysql_com.h9
-rw-r--r--include/sslopt-longopts.h12
-rw-r--r--include/sslopt-vars.h19
-rw-r--r--include/violite.h1
-rw-r--r--libmysql/Makefile.am2
-rw-r--r--libmysql/get_password.c4
-rw-r--r--libmysql_r/Makefile.am2
-rw-r--r--libmysqld/CMakeLists.txt2
-rw-r--r--libmysqld/Makefile.am14
-rw-r--r--libmysqld/examples/Makefile.am2
-rw-r--r--mysql-test/extra/binlog_tests/binlog.test6
-rw-r--r--mysql-test/extra/binlog_tests/innodb_stat.test2
-rw-r--r--mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test93
-rw-r--r--mysql-test/extra/rpl_tests/rpl_insert_id.test2
-rw-r--r--mysql-test/include/common-tests.inc4
-rw-r--r--mysql-test/install_test_db.sh7
-rw-r--r--mysql-test/lib/init_db.sql2
-rw-r--r--mysql-test/lib/mtr_misc.pl9
-rwxr-xr-xmysql-test/mysql-test-run.pl23
-rw-r--r--mysql-test/mysql-test-run.sh13
-rw-r--r--mysql-test/r/archive.result2
-rw-r--r--mysql-test/r/auto_increment.result6
-rw-r--r--mysql-test/r/binlog_row_mix_innodb_myisam.result158
-rw-r--r--mysql-test/r/binlog_stm_mix_innodb_myisam.result103
-rw-r--r--mysql-test/r/compress.result4
-rw-r--r--mysql-test/r/contributors.result5
-rw-r--r--mysql-test/r/create.result46
-rw-r--r--mysql-test/r/ctype_sjis.result4
-rw-r--r--mysql-test/r/events.result121
-rw-r--r--mysql-test/r/events_bugs.result8
-rw-r--r--mysql-test/r/events_grant.result121
-rw-r--r--mysql-test/r/events_logs_tests.result25
-rw-r--r--mysql-test/r/events_microsec.result46
-rw-r--r--mysql-test/r/events_scheduling.result11
-rw-r--r--mysql-test/r/events_stress.result69
-rw-r--r--mysql-test/r/explain.result4
-rw-r--r--mysql-test/r/federated.result1
-rw-r--r--mysql-test/r/flush.result7
-rw-r--r--mysql-test/r/func_gconcat.result6
-rw-r--r--mysql-test/r/func_in.result17
-rw-r--r--mysql-test/r/func_str.result6
-rw-r--r--mysql-test/r/func_time.result1
-rw-r--r--mysql-test/r/grant.result247
-rw-r--r--mysql-test/r/having.result2
-rw-r--r--mysql-test/r/heap.result13
-rw-r--r--mysql-test/r/heap_btree.result3
-rw-r--r--mysql-test/r/im_cmd_line.result40
-rw-r--r--mysql-test/r/im_daemon_life_cycle.result2
-rw-r--r--mysql-test/r/im_instance_conf.result196
-rw-r--r--mysql-test/r/im_life_cycle.result72
-rw-r--r--mysql-test/r/im_options.result150
-rw-r--r--mysql-test/r/im_options_set.result20
-rw-r--r--mysql-test/r/im_options_unset.result15
-rw-r--r--mysql-test/r/im_utils.result6
-rw-r--r--mysql-test/r/information_schema.result13
-rw-r--r--mysql-test/r/information_schema_db.result57
-rw-r--r--mysql-test/r/information_schema_part.result29
-rw-r--r--mysql-test/r/innodb.result2
-rw-r--r--mysql-test/r/innodb_mysql.result274
-rw-r--r--mysql-test/r/insert.result26
-rw-r--r--mysql-test/r/join_outer.result35
-rw-r--r--mysql-test/r/key_cache.result4
-rw-r--r--mysql-test/r/loaddata.result9
-rw-r--r--mysql-test/r/lock_multi.result24
-rw-r--r--mysql-test/r/log_tables.result26
-rw-r--r--mysql-test/r/multi_update.result80
-rw-r--r--mysql-test/r/mysqlbinlog.result7
-rw-r--r--mysql-test/r/mysqlcheck.result1
-rw-r--r--mysql-test/r/mysqldump.result40
-rw-r--r--mysql-test/r/ndb_alter_table.result23
-rw-r--r--mysql-test/r/ndb_autodiscover3.result4
-rw-r--r--mysql-test/r/ndb_basic.result56
-rw-r--r--mysql-test/r/ndb_blob.result66
-rw-r--r--mysql-test/r/ndb_dd_backuprestore.result323
-rw-r--r--mysql-test/r/ndb_dd_basic.result2
-rw-r--r--mysql-test/r/ndb_index_unique.result2
-rw-r--r--mysql-test/r/ndb_rename.result24
-rw-r--r--mysql-test/r/ndb_replace.result2
-rw-r--r--mysql-test/r/not_embedded_server.result1
-rw-r--r--mysql-test/r/partition.result45
-rw-r--r--mysql-test/r/partition_02myisam.result4
-rw-r--r--mysql-test/r/partition_error.result23
-rw-r--r--mysql-test/r/partition_pruning.result27
-rw-r--r--mysql-test/r/preload.result4
-rw-r--r--mysql-test/r/ps_1general.result2
-rw-r--r--mysql-test/r/rpl_ddl.result4
-rw-r--r--mysql-test/r/rpl_ndb_2myisam.result4
-rw-r--r--mysql-test/r/rpl_ndb_dd_partitions.result726
-rw-r--r--mysql-test/r/rpl_ndb_log.result4
-rw-r--r--mysql-test/r/rpl_stm_until.result148
-rw-r--r--mysql-test/r/rpl_temporary.result14
-rw-r--r--mysql-test/r/select.result14
-rw-r--r--mysql-test/r/skip_name_resolve.result1
-rw-r--r--mysql-test/r/sp-threads.result1
-rw-r--r--mysql-test/r/sp.result30
-rw-r--r--mysql-test/r/sp_notembedded.result2
-rw-r--r--mysql-test/r/ssl.result4
-rw-r--r--mysql-test/r/ssl_compress.result4
-rw-r--r--mysql-test/r/status.result10
-rw-r--r--mysql-test/r/strict.result10
-rw-r--r--mysql-test/r/subselect.result27
-rw-r--r--mysql-test/r/system_mysql_db.result2
-rw-r--r--mysql-test/r/type_ranges.result4
-rw-r--r--mysql-test/r/variables.result30
-rw-r--r--mysql-test/r/view.result78
-rw-r--r--mysql-test/r/view_grant.result87
-rw-r--r--mysql-test/std_data/bug15328.cnf2
-rw-r--r--mysql-test/t/archive.test2
-rw-r--r--mysql-test/t/auto_increment.test11
-rw-r--r--mysql-test/t/contributors.test1
-rw-r--r--mysql-test/t/create.test37
-rw-r--r--mysql-test/t/ctype_sjis.test2
-rw-r--r--mysql-test/t/disabled.def26
-rw-r--r--mysql-test/t/events.test135
-rw-r--r--mysql-test/t/events_bugs.test22
-rw-r--r--mysql-test/t/events_grant.test105
-rw-r--r--mysql-test/t/events_logs_tests.test22
-rw-r--r--mysql-test/t/events_microsec.test50
-rw-r--r--mysql-test/t/events_scheduling.test10
-rw-r--r--mysql-test/t/events_stress.test118
-rw-r--r--mysql-test/t/explain.test4
-rw-r--r--mysql-test/t/federated.test57
-rw-r--r--mysql-test/t/flush.test40
-rw-r--r--mysql-test/t/func_gconcat.test4
-rw-r--r--mysql-test/t/func_group.test1
-rw-r--r--mysql-test/t/func_in.test12
-rw-r--r--mysql-test/t/func_str.test6
-rw-r--r--mysql-test/t/func_time.test1
-rw-r--r--mysql-test/t/grant.test159
-rw-r--r--mysql-test/t/group_min_max.test3
-rw-r--r--mysql-test/t/heap.test12
-rw-r--r--mysql-test/t/heap_btree.test8
-rw-r--r--mysql-test/t/im_cmd_line.imtest68
-rw-r--r--mysql-test/t/im_daemon_life_cycle-im.opt1
-rw-r--r--mysql-test/t/im_daemon_life_cycle.imtest3
-rw-r--r--mysql-test/t/im_instance_conf-im.opt1
-rw-r--r--mysql-test/t/im_instance_conf.imtest228
-rw-r--r--mysql-test/t/im_life_cycle-im.opt1
-rw-r--r--mysql-test/t/im_life_cycle.imtest95
-rw-r--r--mysql-test/t/im_options.imtest268
-rw-r--r--mysql-test/t/im_options_set.imtest142
-rw-r--r--mysql-test/t/im_options_unset.imtest150
-rw-r--r--mysql-test/t/im_utils-im.opt1
-rw-r--r--mysql-test/t/im_utils.imtest8
-rw-r--r--mysql-test/t/information_schema.test21
-rw-r--r--mysql-test/t/information_schema_chmod.test3
-rw-r--r--mysql-test/t/information_schema_db.test60
-rw-r--r--mysql-test/t/information_schema_part.test22
-rw-r--r--mysql-test/t/innodb_mysql.test216
-rw-r--r--mysql-test/t/insert.test29
-rw-r--r--mysql-test/t/join_outer.test18
-rw-r--r--mysql-test/t/loaddata.test4
-rw-r--r--mysql-test/t/lock_multi.test65
-rw-r--r--mysql-test/t/log_tables.test11
-rw-r--r--mysql-test/t/multi_update.test30
-rw-r--r--mysql-test/t/mysqlbinlog.test14
-rw-r--r--mysql-test/t/mysqlcheck.test4
-rw-r--r--mysql-test/t/mysqldump.test20
-rw-r--r--mysql-test/t/ndb_alter_table.test17
-rw-r--r--mysql-test/t/ndb_autodiscover3.test4
-rw-r--r--mysql-test/t/ndb_basic.test14
-rw-r--r--mysql-test/t/ndb_blob.test56
-rw-r--r--mysql-test/t/ndb_dd_backuprestore.test170
-rw-r--r--mysql-test/t/ndb_rename.test36
-rw-r--r--mysql-test/t/partition.test51
-rw-r--r--mysql-test/t/partition_error.test28
-rw-r--r--mysql-test/t/partition_mgm_err2.test2
-rw-r--r--mysql-test/t/partition_pruning.test26
-rw-r--r--mysql-test/t/ps_1general.test6
-rw-r--r--mysql-test/t/rpl_ndb_2innodb-master.opt2
-rw-r--r--mysql-test/t/rpl_ndb_2innodb-slave.opt2
-rw-r--r--mysql-test/t/rpl_ndb_2myisam-master.opt2
-rw-r--r--mysql-test/t/rpl_ndb_2myisam-slave.opt2
-rw-r--r--mysql-test/t/rpl_ndb_dd_partitions.test310
-rw-r--r--mysql-test/t/rpl_ndb_innodb2ndb-master.opt2
-rw-r--r--mysql-test/t/rpl_ndb_innodb2ndb-slave.opt2
-rw-r--r--mysql-test/t/rpl_ndb_myisam2ndb-slave.opt2
-rw-r--r--mysql-test/t/rpl_stm_until.test8
-rw-r--r--mysql-test/t/rpl_temporary.test40
-rw-r--r--mysql-test/t/select.test19
-rw-r--r--mysql-test/t/sp.test46
-rw-r--r--mysql-test/t/strict.test10
-rw-r--r--mysql-test/t/subselect.test31
-rw-r--r--mysql-test/t/variables.test39
-rw-r--r--mysql-test/t/view.test70
-rw-r--r--mysql-test/t/view_grant.test97
-rw-r--r--mysql-test/t/wait_timeout.test68
-rw-r--r--mysql-test/valgrind.supp48
-rw-r--r--mysql-test/valgrind.supp.orig189
-rw-r--r--mysys/Makefile.am8
-rw-r--r--mysys/base64.c3
-rw-r--r--mysys/default.c14
-rw-r--r--mysys/default_modify.c58
-rw-r--r--mysys/mf_keycache.c8
-rw-r--r--mysys/mf_path.c2
-rw-r--r--mysys/mf_tempfile.c2
-rw-r--r--mysys/my_access.c4
-rw-r--r--mysys/my_atomic.c46
-rw-r--r--mysys/my_bitmap.c210
-rw-r--r--mysys/my_clock.c2
-rw-r--r--mysys/my_copy.c2
-rw-r--r--mysys/my_create.c9
-rw-r--r--mysys/my_dup.c2
-rw-r--r--mysys/my_gethostbyname.c2
-rw-r--r--mysys/my_getncpus.c40
-rw-r--r--mysys/my_getopt.c2
-rw-r--r--mysys/my_getwd.c36
-rw-r--r--mysys/my_init.c2
-rw-r--r--mysys/my_lib.c114
-rw-r--r--mysys/my_net.c4
-rw-r--r--mysys/my_open.c4
-rw-r--r--mysys/my_redel.c4
-rw-r--r--mysys/thr_lock.c14
-rw-r--r--plugin/fulltext/Makefile.am2
-rw-r--r--plugin/fulltext/plugin_example.c5
-rw-r--r--scripts/Makefile.am3
-rw-r--r--scripts/make_binary_distribution.sh2
-rw-r--r--scripts/make_sharedlib_distribution.sh6
-rw-r--r--scripts/make_win_src_distribution.sh1
-rw-r--r--scripts/mysql_create_system_tables.sh2
-rw-r--r--scripts/mysql_explain_log.sh392
-rw-r--r--scripts/mysql_fix_privilege_tables.sql4
-rw-r--r--server-tools/instance-manager/CMakeLists.txt1
-rw-r--r--server-tools/instance-manager/IMService.cpp32
-rw-r--r--server-tools/instance-manager/IMService.h20
-rw-r--r--server-tools/instance-manager/Makefile.am7
-rw-r--r--server-tools/instance-manager/WindowsService.cpp33
-rw-r--r--server-tools/instance-manager/WindowsService.h18
-rw-r--r--server-tools/instance-manager/command.h18
-rw-r--r--server-tools/instance-manager/commands.cc1854
-rw-r--r--server-tools/instance-manager/commands.h303
-rw-r--r--server-tools/instance-manager/exit_codes.h41
-rw-r--r--server-tools/instance-manager/guardian.cc155
-rw-r--r--server-tools/instance-manager/guardian.h34
-rw-r--r--server-tools/instance-manager/instance.cc122
-rw-r--r--server-tools/instance-manager/instance.h118
-rw-r--r--server-tools/instance-manager/instance_map.cc436
-rw-r--r--server-tools/instance-manager/instance_map.h61
-rw-r--r--server-tools/instance-manager/instance_options.cc325
-rw-r--r--server-tools/instance-manager/instance_options.h60
-rw-r--r--server-tools/instance-manager/listener.cc25
-rw-r--r--server-tools/instance-manager/listener.h4
-rw-r--r--server-tools/instance-manager/log.cc12
-rw-r--r--server-tools/instance-manager/manager.cc184
-rw-r--r--server-tools/instance-manager/manager.h4
-rw-r--r--server-tools/instance-manager/messages.cc24
-rw-r--r--server-tools/instance-manager/mysql_connection.cc46
-rw-r--r--server-tools/instance-manager/mysql_manager_error.h8
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc84
-rw-r--r--server-tools/instance-manager/options.cc426
-rw-r--r--server-tools/instance-manager/options.h95
-rw-r--r--server-tools/instance-manager/parse.cc351
-rw-r--r--server-tools/instance-manager/parse.h159
-rw-r--r--server-tools/instance-manager/parse_output.cc8
-rw-r--r--server-tools/instance-manager/parse_output.h2
-rw-r--r--server-tools/instance-manager/portability.h14
-rw-r--r--server-tools/instance-manager/priv.cc8
-rw-r--r--server-tools/instance-manager/priv.h30
-rw-r--r--server-tools/instance-manager/protocol.cc8
-rw-r--r--server-tools/instance-manager/protocol.h5
-rw-r--r--server-tools/instance-manager/thread_registry.cc11
-rw-r--r--server-tools/instance-manager/user_management_commands.cc406
-rw-r--r--server-tools/instance-manager/user_management_commands.h167
-rw-r--r--server-tools/instance-manager/user_map.cc325
-rw-r--r--server-tools/instance-manager/user_map.h63
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/Makefile.am9
-rw-r--r--sql/authors.h4
-rw-r--r--sql/contributors.h40
-rw-r--r--sql/discover.cc2
-rw-r--r--sql/event.cc1109
-rw-r--r--sql/event.h332
-rw-r--r--sql/event_executor.cc995
-rw-r--r--sql/event_priv.h70
-rw-r--r--sql/event_scheduler.cc2432
-rw-r--r--sql/event_scheduler.h254
-rw-r--r--sql/event_timed.cc630
-rw-r--r--sql/field.cc216
-rw-r--r--sql/field.h11
-rw-r--r--sql/filesort.cc106
-rw-r--r--sql/ha_berkeley.cc162
-rw-r--r--sql/ha_berkeley.h10
-rw-r--r--sql/ha_federated.cc342
-rw-r--r--sql/ha_federated.h97
-rw-r--r--sql/ha_heap.cc112
-rw-r--r--sql/ha_heap.h15
-rw-r--r--sql/ha_innodb.cc196
-rw-r--r--sql/ha_innodb.h26
-rw-r--r--sql/ha_myisam.cc146
-rw-r--r--sql/ha_myisam.h8
-rw-r--r--sql/ha_myisammrg.cc98
-rw-r--r--sql/ha_myisammrg.h7
-rw-r--r--sql/ha_ndbcluster.cc404
-rw-r--r--sql/ha_ndbcluster.h40
-rw-r--r--sql/ha_ndbcluster_binlog.cc668
-rw-r--r--sql/ha_ndbcluster_binlog.h5
-rw-r--r--sql/ha_partition.cc311
-rw-r--r--sql/ha_partition.h38
-rw-r--r--sql/handler.cc820
-rw-r--r--sql/handler.h447
-rw-r--r--sql/item.cc91
-rw-r--r--sql/item.h73
-rw-r--r--sql/item_cmpfunc.cc71
-rw-r--r--sql/item_cmpfunc.h19
-rw-r--r--sql/item_func.cc9
-rw-r--r--sql/item_func.h34
-rw-r--r--sql/item_row.cc6
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.h32
-rw-r--r--sql/item_subselect.cc44
-rw-r--r--sql/item_subselect.h1
-rw-r--r--sql/item_sum.cc9
-rw-r--r--sql/item_sum.h2
-rw-r--r--sql/item_timefunc.cc36
-rw-r--r--sql/item_timefunc.h30
-rw-r--r--sql/item_xmlfunc.h1
-rw-r--r--sql/key.cc19
-rw-r--r--sql/lex.h2
-rw-r--r--sql/lock.cc34
-rw-r--r--sql/log.cc111
-rw-r--r--sql/log_event.cc103
-rw-r--r--sql/log_event.h8
-rw-r--r--sql/mysql_priv.h41
-rw-r--r--sql/mysqld.cc152
-rw-r--r--sql/net_serv.cc9
-rw-r--r--sql/opt_range.cc468
-rw-r--r--sql/opt_range.h9
-rw-r--r--sql/opt_sum.cc61
-rw-r--r--sql/partition_element.h16
-rw-r--r--sql/partition_info.cc53
-rw-r--r--sql/protocol.cc11
-rw-r--r--sql/records.cc11
-rw-r--r--sql/repl_failsafe.cc3
-rw-r--r--sql/set_var.cc141
-rw-r--r--sql/set_var.h36
-rw-r--r--sql/share/errmsg.txt42
-rw-r--r--sql/slave.cc243
-rw-r--r--sql/sp.cc16
-rw-r--r--sql/sp_head.cc8
-rw-r--r--sql/spatial.cc7
-rw-r--r--sql/spatial.h2
-rw-r--r--sql/sql_acl.cc212
-rw-r--r--sql/sql_base.cc253
-rw-r--r--sql/sql_bitmap.h2
-rw-r--r--sql/sql_class.cc74
-rw-r--r--sql/sql_class.h64
-rw-r--r--sql/sql_db.cc62
-rw-r--r--sql/sql_delete.cc32
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_error.h2
-rw-r--r--sql/sql_handler.cc13
-rw-r--r--sql/sql_help.cc28
-rw-r--r--sql/sql_insert.cc330
-rw-r--r--sql/sql_lex.cc139
-rw-r--r--sql/sql_lex.h155
-rw-r--r--sql/sql_load.cc63
-rw-r--r--sql/sql_olap.cc8
-rw-r--r--sql/sql_parse.cc152
-rw-r--r--sql/sql_partition.cc93
-rw-r--r--sql/sql_partition.h3
-rw-r--r--sql/sql_plugin.cc53
-rw-r--r--sql/sql_plugin.h5
-rw-r--r--sql/sql_prepare.cc11
-rw-r--r--sql/sql_repl.cc17
-rw-r--r--sql/sql_select.cc334
-rw-r--r--sql/sql_select.h23
-rw-r--r--sql/sql_show.cc501
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_table.cc149
-rw-r--r--sql/sql_tablespace.cc10
-rw-r--r--sql/sql_trigger.cc4
-rw-r--r--sql/sql_trigger.h6
-rw-r--r--sql/sql_udf.cc7
-rw-r--r--sql/sql_union.cc10
-rw-r--r--sql/sql_update.cc142
-rw-r--r--sql/sql_view.cc21
-rw-r--r--sql/sql_yacc.yy51
-rw-r--r--sql/structs.h16
-rw-r--r--sql/table.cc417
-rw-r--r--sql/table.h77
-rw-r--r--sql/time.cc1
-rw-r--r--sql/tztime.cc11
-rw-r--r--storage/archive/ha_archive.cc177
-rw-r--r--storage/archive/ha_archive.h11
-rw-r--r--storage/blackhole/ha_blackhole.cc88
-rw-r--r--storage/blackhole/ha_blackhole.h8
-rw-r--r--storage/csv/ha_tina.cc128
-rw-r--r--storage/csv/ha_tina.h12
-rw-r--r--storage/example/ha_example.cc75
-rw-r--r--storage/example/ha_example.h4
-rw-r--r--storage/heap/hp_create.c2
-rw-r--r--storage/heap/hp_extra.c17
-rw-r--r--storage/heap/hp_test2.c2
-rw-r--r--storage/heap/hp_write.c2
-rw-r--r--storage/myisam/ft_boolean_search.c50
-rw-r--r--storage/myisam/ft_nlq_search.c8
-rw-r--r--storage/myisam/ft_parser.c40
-rw-r--r--storage/myisam/ft_static.c2
-rw-r--r--storage/myisam/ft_update.c54
-rw-r--r--storage/myisam/ftdefs.h14
-rw-r--r--storage/myisam/mi_check.c74
-rw-r--r--storage/myisam/mi_extra.c56
-rw-r--r--storage/myisam/mi_key.c14
-rw-r--r--storage/myisam/mi_search.c38
-rw-r--r--storage/myisam/mi_test2.c4
-rw-r--r--storage/myisam/mi_update.c3
-rw-r--r--storage/myisam/mi_write.c3
-rw-r--r--storage/myisam/myisamdef.h18
-rw-r--r--storage/myisam/myisampack.c4
-rw-r--r--storage/myisam/sort.c1
-rw-r--r--storage/myisammrg/myrg_extra.c26
-rw-r--r--storage/ndb/include/mgmapi/mgmapi.h10
-rw-r--r--storage/ndb/include/ndbapi/Ndb.hpp79
-rw-r--r--storage/ndb/include/ndbapi/NdbDictionary.hpp13
-rw-r--r--storage/ndb/include/util/SocketServer.hpp8
-rw-r--r--storage/ndb/src/common/util/SocketServer.cpp44
-rw-r--r--storage/ndb/src/common/util/socket_io.cpp70
-rw-r--r--storage/ndb/src/kernel/blocks/ERROR_codes.txt3
-rw-r--r--storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp24
-rw-r--r--storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp8
-rw-r--r--storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp6
-rw-r--r--storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp10
-rw-r--r--storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp2
-rw-r--r--storage/ndb/src/kernel/blocks/suma/Suma.cpp17
-rw-r--r--storage/ndb/src/kernel/vm/Configuration.cpp8
-rw-r--r--storage/ndb/src/mgmapi/mgmapi.cpp27
-rw-r--r--storage/ndb/src/mgmsrv/Services.cpp13
-rw-r--r--storage/ndb/src/mgmsrv/Services.hpp1
-rw-r--r--storage/ndb/src/ndbapi/DictCache.cpp1
-rw-r--r--storage/ndb/src/ndbapi/DictCache.hpp4
-rw-r--r--storage/ndb/src/ndbapi/Ndb.cpp384
-rw-r--r--storage/ndb/src/ndbapi/NdbDictionary.cpp8
-rw-r--r--storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp89
-rw-r--r--storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp198
-rw-r--r--storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp339
-rw-r--r--storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp12
-rw-r--r--storage/ndb/src/ndbapi/NdbImpl.hpp2
-rw-r--r--storage/ndb/src/ndbapi/NdbTransaction.cpp9
-rw-r--r--storage/ndb/src/ndbapi/Ndbif.cpp4
-rw-r--r--storage/ndb/src/ndbapi/Ndbinit.cpp7
-rw-r--r--storage/ndb/src/ndbapi/ndberror.c1
-rw-r--r--storage/ndb/test/ndbapi/Makefile.am2
-rw-r--r--storage/ndb/test/ndbapi/testDict.cpp10
-rw-r--r--storage/ndb/test/ndbapi/testInterpreter.cpp202
-rw-r--r--storage/ndb/test/ndbapi/testNodeRestart.cpp56
-rw-r--r--storage/ndb/test/run-test/daily-basic-tests.txt4
-rw-r--r--storage/ndb/tools/restore/consumer_restore.cpp9
-rw-r--r--support-files/mysql.server.sh5
-rw-r--r--support-files/mysql.spec.sh15
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/mysql_client_test.c21
-rw-r--r--unittest/Makefile.am28
-rw-r--r--unittest/README.txt23
-rw-r--r--unittest/examples/Makefile.am11
-rw-r--r--unittest/examples/no_plan-t.c (renamed from unittest/examples/no_plan.t.c)0
-rw-r--r--unittest/examples/simple-t.c (renamed from unittest/examples/simple.t.c)0
-rw-r--r--unittest/examples/skip-t.c (renamed from unittest/examples/skip.t.c)0
-rw-r--r--unittest/examples/skip_all-t.c (renamed from unittest/examples/skip_all.t.c)0
-rw-r--r--unittest/examples/todo-t.c (renamed from unittest/examples/todo.t.c)0
-rw-r--r--unittest/mysys/Makefile.am6
-rw-r--r--unittest/mysys/base64-t.c (renamed from unittest/mysys/base64.t.c)2
-rw-r--r--unittest/mysys/bitmap-t.c (renamed from unittest/mysys/bitmap.t.c)0
-rw-r--r--unittest/mysys/my_atomic-t.c149
-rw-r--r--unittest/mytap/t/Makefile.am5
-rw-r--r--unittest/mytap/t/basic-t.c (renamed from unittest/mytap/t/basic.t.c)2
-rw-r--r--unittest/unit.pl2
-rw-r--r--vio/Makefile.am2
-rw-r--r--vio/viosocket.c23
539 files changed, 23727 insertions, 12144 deletions
diff --git a/.bzrignore b/.bzrignore
index 095c04b36ee..835e4b2c357 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,3 +1,4 @@
+*-t
*.a
*.bb
*.bbg
@@ -458,6 +459,7 @@ libmysqld/emb_qcache.cpp
libmysqld/errmsg.c
libmysqld/event.cc
libmysqld/event_executor.cc
+libmysqld/event_scheduler.cc
libmysqld/event_timed.cc
libmysqld/examples/client_test.c
libmysqld/examples/client_test.cc
@@ -788,6 +790,8 @@ mysys/main.cc
mysys/my_new.cpp
mysys/raid.cpp
mysys/ste5KbMa
+mysys/test_atomic
+mysys/test_bitmap
mysys/test_charset
mysys/test_dir
mysys/test_gethwaddr
diff --git a/BUILD/compile-pentium-gcov b/BUILD/compile-pentium-gcov
index 05cb0bb0d78..b024bba49bf 100755
--- a/BUILD/compile-pentium-gcov
+++ b/BUILD/compile-pentium-gcov
@@ -3,8 +3,19 @@
path=`dirname $0`
. "$path/SETUP.sh"
-extra_flags="$pentium_cflags -fprofile-arcs -ftest-coverage"
+# Need to disable ccache, or we loose the gcov-needed compiler output files.
+CCACHE_DISABLE=1
+export CCACHE_DISABLE
+
+# GCC4 needs -fprofile-arcs -ftest-coverage on the linker command line (as well
+# as on the compiler command line), and this requires setting LDFLAGS for BDB.
+export LDFLAGS="-fprofile-arcs -ftest-coverage"
+
+# The -fprofile-arcs and -ftest-coverage options cause GCC to instrument the
+# code with profiling information used by gcov.
+# the -DDISABLE_TAO_ASM is needed to avoid build failures in Yassl.
+extra_flags="$pentium_cflags -fprofile-arcs -ftest-coverage -DDISABLE_TAO_ASM"
extra_configs="$pentium_configs $debug_configs --disable-shared $static_link"
-extra_configs="$extra_configs --with-innodb --with-berkeley-db"
+extra_configs="$extra_configs $max_configs"
. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium64 b/BUILD/compile-pentium64
new file mode 100755
index 00000000000..e45528d3b45
--- /dev/null
+++ b/BUILD/compile-pentium64
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh" $@ --with-debug=full
+
+extra_flags="$pentium64_cflags $fast_cflags"
+c_warnings="$c_warnings"
+cxx_warnings="$cxx_warnings"
+extra_configs="$pentium_configs $static_link"
+
+extra_configs="$extra_configs "
+CC="$CC --pipe"
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium64-debug b/BUILD/compile-pentium64-debug
index 761c590b680..145d5c44f82 100755
--- a/BUILD/compile-pentium64-debug
+++ b/BUILD/compile-pentium64-debug
@@ -7,5 +7,5 @@ extra_flags="$pentium64_cflags $debug_cflags"
extra_configs="$pentium_configs $debug_configs $static_link"
extra_configs="$extra_configs "
-
+CC="$CC --pipe"
. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium64-debug-max b/BUILD/compile-pentium64-debug-max
index 594fe2e3009..7b71237cb2f 100755
--- a/BUILD/compile-pentium64-debug-max
+++ b/BUILD/compile-pentium64-debug-max
@@ -7,5 +7,5 @@ extra_flags="$pentium64_cflags $debug_cflags"
extra_configs="$pentium_configs $debug_configs $max_configs"
extra_configs="$extra_configs "
-
+CC="$CC --pipe"
. "$path/FINISH.sh"
diff --git a/BitKeeper/triggers/pre-outgoing.crash-protect.pl b/BitKeeper/triggers/pre-outgoing.crash-protect.pl
new file mode 100755
index 00000000000..bbaa092e335
--- /dev/null
+++ b/BitKeeper/triggers/pre-outgoing.crash-protect.pl
@@ -0,0 +1,85 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+my $event= $ENV{BK_EVENT};
+unless($event eq 'outgoing pull' || $event eq 'outgoing push' ||
+ $event eq 'resolve') {
+ exit 0;
+}
+
+print "Checking for bad changesets from old crashed 5.1 tree...\n";
+
+my @bad_csets=
+ ( 'monty@mysql.com|ChangeSet|20060418090255|16983',
+ 'monty@mysql.com|ChangeSet|20060418090458|02628',
+ 'monty@mysql.com|ChangeSet|20060419084236|49576',
+ 'monty@mysql.com|ChangeSet|20060503164655|51444',
+ 'monty@mysql.com|ChangeSet|20060503225814|60133',
+ 'monty@mysql.com|ChangeSet|20060504033006|54878',
+ 'monty@mysql.com|ChangeSet|20060504130520|48660',
+ 'monty@mysql.com|ChangeSet|20060504164102|03511',
+ 'monty@mysql.com|ChangeSet|20060504193112|04109',
+ 'monty@mysql.com|ChangeSet|20060505015314|02799',
+ 'monty@mysql.com|ChangeSet|20060505084007|16704',
+ 'monty@mysql.com|ChangeSet|20060505104008|16695',
+ 'monty@mysql.com|ChangeSet|20060505171041|13924',
+ 'monty@mysql.com|ChangeSet|20060508121933|13866',
+ 'monty@mysql.com|ChangeSet|20060508160902|15029',
+ 'monty@mysql.com|ChangeSet|20060509145448|38636',
+ 'monty@mysql.com|ChangeSet|20060509224111|40037',
+ 'monty@mysql.com|ChangeSet|20060510090758|40678',
+ 'monty@mysql.com|ChangeSet|20060515164104|46760',
+ 'monty@mysql.com|ChangeSet|20060530114549|35852',
+ 'monty@mysql.com|ChangeSet|20060605032828|23579',
+ 'monty@mysql.com|ChangeSet|20060605033011|10641',
+ 'monty@mysql.com|ChangeSet|20060605060652|09843',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605094744|10838',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605105746|11800',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605122345|12772',
+ 'jmiller@mysql.com|ChangeSet|20060531210831|36442',
+ 'jmiller@mysql.com|ChangeSet|20060602151941|36118',
+ 'jmiller@mysql.com|ChangeSet|20060602152136|27762',
+ 'jmiller@mysql.com|ChangeSet|20060605121748|12864',
+ 'jmiller@mysql.com|ChangeSet|20060605160304|14798',
+ 'jimw@mysql.com|ChangeSet|20060605210201|14667',
+ 'igor@rurik.mysql.com|ChangeSet|20060605220727|15265',
+ 'igor@rurik.mysql.com|ChangeSet|20060605221206|15134',
+ 'stewart@mysql.com|ChangeSet|20060525073521|11169',
+ 'stewart@mysql.com|ChangeSet|20060605154220|12975',
+ 'stewart@mysql.com|ChangeSet|20060606040001|15337',
+ );
+
+# Read the list of changesets.
+my $csetlist = $ENV{BK_CSETLIST};
+if(!defined($csetlist) || !open(FH, '<', $csetlist)) {
+ die "Failed to open list of incoming changesets '$csetlist': $!.\n";
+}
+my @csets = <FH>;
+close FH;
+
+# Reject any attempt to push/pull a bad changeset.
+for my $cs (@csets) {
+ # Do this the raw way, don't want to be bitten by different EOL conventions
+ # on server and client (Unix/Windows/Mac).
+ $cs =~ s/\x0d?\x0a?$//s;
+ if(grep($_ eq $cs, @bad_csets)) {
+ print <<END;
+BAD CHANGESET DETECTED! $event REJECTED!
+
+The changeset with key '$cs' was detected in the attempted push or pull.
+This changeset is from the corrupt part of the crashed mysql-5.1-new tree.
+Pushing or pulling this changeset would result in corruption of the new tree,
+and therefore the operation has been rejected.
+
+Contact Kristian Nielsen (knielsen\@mysql.com, IRC knielsen) if you have any
+questions regarding this.
+END
+ exit 1;
+ }
+}
+
+print "No bad changesets found, proceeding.\n";
+
+exit 0;
diff --git a/BitKeeper/triggers/pre-resolve.crash-protect.pl b/BitKeeper/triggers/pre-resolve.crash-protect.pl
new file mode 100755
index 00000000000..bbaa092e335
--- /dev/null
+++ b/BitKeeper/triggers/pre-resolve.crash-protect.pl
@@ -0,0 +1,85 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+my $event= $ENV{BK_EVENT};
+unless($event eq 'outgoing pull' || $event eq 'outgoing push' ||
+ $event eq 'resolve') {
+ exit 0;
+}
+
+print "Checking for bad changesets from old crashed 5.1 tree...\n";
+
+my @bad_csets=
+ ( 'monty@mysql.com|ChangeSet|20060418090255|16983',
+ 'monty@mysql.com|ChangeSet|20060418090458|02628',
+ 'monty@mysql.com|ChangeSet|20060419084236|49576',
+ 'monty@mysql.com|ChangeSet|20060503164655|51444',
+ 'monty@mysql.com|ChangeSet|20060503225814|60133',
+ 'monty@mysql.com|ChangeSet|20060504033006|54878',
+ 'monty@mysql.com|ChangeSet|20060504130520|48660',
+ 'monty@mysql.com|ChangeSet|20060504164102|03511',
+ 'monty@mysql.com|ChangeSet|20060504193112|04109',
+ 'monty@mysql.com|ChangeSet|20060505015314|02799',
+ 'monty@mysql.com|ChangeSet|20060505084007|16704',
+ 'monty@mysql.com|ChangeSet|20060505104008|16695',
+ 'monty@mysql.com|ChangeSet|20060505171041|13924',
+ 'monty@mysql.com|ChangeSet|20060508121933|13866',
+ 'monty@mysql.com|ChangeSet|20060508160902|15029',
+ 'monty@mysql.com|ChangeSet|20060509145448|38636',
+ 'monty@mysql.com|ChangeSet|20060509224111|40037',
+ 'monty@mysql.com|ChangeSet|20060510090758|40678',
+ 'monty@mysql.com|ChangeSet|20060515164104|46760',
+ 'monty@mysql.com|ChangeSet|20060530114549|35852',
+ 'monty@mysql.com|ChangeSet|20060605032828|23579',
+ 'monty@mysql.com|ChangeSet|20060605033011|10641',
+ 'monty@mysql.com|ChangeSet|20060605060652|09843',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605094744|10838',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605105746|11800',
+ 'msvensson@neptunus.(none)|ChangeSet|20060605122345|12772',
+ 'jmiller@mysql.com|ChangeSet|20060531210831|36442',
+ 'jmiller@mysql.com|ChangeSet|20060602151941|36118',
+ 'jmiller@mysql.com|ChangeSet|20060602152136|27762',
+ 'jmiller@mysql.com|ChangeSet|20060605121748|12864',
+ 'jmiller@mysql.com|ChangeSet|20060605160304|14798',
+ 'jimw@mysql.com|ChangeSet|20060605210201|14667',
+ 'igor@rurik.mysql.com|ChangeSet|20060605220727|15265',
+ 'igor@rurik.mysql.com|ChangeSet|20060605221206|15134',
+ 'stewart@mysql.com|ChangeSet|20060525073521|11169',
+ 'stewart@mysql.com|ChangeSet|20060605154220|12975',
+ 'stewart@mysql.com|ChangeSet|20060606040001|15337',
+ );
+
+# Read the list of changesets.
+my $csetlist = $ENV{BK_CSETLIST};
+if(!defined($csetlist) || !open(FH, '<', $csetlist)) {
+ die "Failed to open list of incoming changesets '$csetlist': $!.\n";
+}
+my @csets = <FH>;
+close FH;
+
+# Reject any attempt to push/pull a bad changeset.
+for my $cs (@csets) {
+ # Do this the raw way, don't want to be bitten by different EOL conventions
+ # on server and client (Unix/Windows/Mac).
+ $cs =~ s/\x0d?\x0a?$//s;
+ if(grep($_ eq $cs, @bad_csets)) {
+ print <<END;
+BAD CHANGESET DETECTED! $event REJECTED!
+
+The changeset with key '$cs' was detected in the attempted push or pull.
+This changeset is from the corrupt part of the crashed mysql-5.1-new tree.
+Pushing or pulling this changeset would result in corruption of the new tree,
+and therefore the operation has been rejected.
+
+Contact Kristian Nielsen (knielsen\@mysql.com, IRC knielsen) if you have any
+questions regarding this.
+END
+ exit 1;
+ }
+}
+
+print "No bad changesets found, proceeding.\n";
+
+exit 0;
diff --git a/client/Makefile.am b/client/Makefile.am
index aa78f825c87..ff97243815a 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -32,7 +32,7 @@ endif
INCLUDES = -I$(top_builddir)/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/regex \
- $(openssl_includes) $(yassl_includes)
+ $(openssl_includes)
LIBS = @CLIENT_LIBS@
LDADD= @CLIENT_EXTRA_LDFLAGS@ $(CLIENT_THREAD_LIBS) \
$(top_builddir)/libmysql/libmysqlclient.la
@@ -83,13 +83,13 @@ link_sources:
for f in $(sql_src) ; do \
rm -f $$f; \
@LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \
- done; \
+ done; \
for f in $(strings_src) ; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \
- done; \
- rm -f $(srcdir)/my_user.c; \
- @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c
+ done; \
+ rm -f $(srcdir)/my_user.c; \
+ @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c;
# Don't update the files from bitkeeper
diff --git a/client/client_priv.h.rej b/client/client_priv.h.rej
deleted file mode 100644
index ac3818bb1e1..00000000000
--- a/client/client_priv.h.rej
+++ /dev/null
@@ -1,15 +0,0 @@
-***************
-*** 50,55 ****
- OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING,
- #endif
- OPT_TRIGGERS,
- OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE,
-! OPT_TZ_UTC, OPT_AUTO_CLOSE
- };
---- 50,55 ----
- OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING,
- #endif
- OPT_TRIGGERS,
- OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE,
-! OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_SSL_VERIFY_SERVER_CERT
- };
diff --git a/client/get_password.c b/client/get_password.c
index 1b7b4e65a9f..b643b760718 100644
--- a/client/get_password.c
+++ b/client/get_password.c
@@ -64,7 +64,7 @@
/* were just going to fake it here and get input from
the keyboard */
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
{
char to[80];
char *pos=to,*end=to+sizeof(to)-1;
@@ -150,7 +150,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
#endif /* ! HAVE_GETPASS */
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
{
#ifdef HAVE_GETPASS
char *passbuff;
diff --git a/client/mysql.cc b/client/mysql.cc
index 8b121579cb0..96df1fafc3b 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -2346,7 +2346,6 @@ print_table_data(MYSQL_RES *result)
uint visible_length;
uint extra_padding;
- /* If this column may have a null value, use "NULL" for empty. */
if (! not_null_flag[off] && (cur[off] == NULL))
{
buffer= "NULL";
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 4b2527c25ef..81ad74466eb 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -72,6 +72,7 @@ static int port= 0;
static const char* sock= 0;
static const char* user = 0;
static char* pass = 0;
+static char *charset= 0;
static ulonglong start_position, stop_position;
#define start_position_mot ((my_off_t)start_position)
@@ -733,6 +734,9 @@ static struct my_option my_long_options[] =
"Extract only binlog entries created by the server having the given id.",
(gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"set-charset", OPT_SET_CHARSET,
+ "Add 'SET NAMES character_set' to the output.", (gptr*) &charset,
+ (gptr*) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"short-form", 's', "Just show the queries, no extra info.",
(gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
@@ -1457,6 +1461,13 @@ int main(int argc, char** argv)
"/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
"COMPLETION_TYPE=0*/;\n");
+ if (charset)
+ fprintf(result_file,
+ "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
+ "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
+ "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
+ "\n/*!40101 SET NAMES %s */;\n", charset);
+
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
(--argc >= 0) && !stop_passed ; )
{
@@ -1481,6 +1492,12 @@ int main(int argc, char** argv)
if (disable_log_bin)
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
+ if (charset)
+ fprintf(result_file,
+ "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
+ "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
+ "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
+
if (tmpdir.list)
free_tmpdir(&tmpdir);
if (result_file != stdout)
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 58cd2342bd3..e257e3734a1 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -3063,14 +3063,13 @@ static my_bool dump_all_views_in_db(char *database)
different case (e.g. T1 vs t1)
RETURN
- int - 0 if a tablename was retrieved. 1 if not
+ pointer to the table name
+ 0 if error
*/
-static int get_actual_table_name(const char *old_table_name,
- char *new_table_name,
- int buf_size)
+static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
{
- int retval;
+ char *name= 0;
MYSQL_RES *table_res;
MYSQL_ROW row;
char query[50 + 2*NAME_LEN];
@@ -3087,66 +3086,55 @@ static int get_actual_table_name(const char *old_table_name,
safe_exit(EX_MYSQLERR);
}
- retval = 1;
-
if ((table_res= mysql_store_result(sock)))
{
my_ulonglong num_rows= mysql_num_rows(table_res);
if (num_rows > 0)
{
+ ulong *lengths;
/*
Return first row
TODO: Return all matching rows
*/
row= mysql_fetch_row(table_res);
- strmake(new_table_name, row[0], buf_size-1);
- retval= 0;
+ lengths= mysql_fetch_lengths(table_res);
+ name= strmake_root(root, row[0], lengths[0]);
}
mysql_free_result(table_res);
}
- DBUG_RETURN(retval);
+ DBUG_PRINT("exit", ("new_table_name: %s", name));
+ DBUG_RETURN(name);
}
static int dump_selected_tables(char *db, char **table_names, int tables)
{
- uint i;
char table_buff[NAME_LEN*+3];
- char new_table_name[NAME_LEN];
DYNAMIC_STRING lock_tables_query;
- HASH dump_tables;
- char *table_name;
+ MEM_ROOT root;
+ char **dump_tables, **pos, **end;
DBUG_ENTER("dump_selected_tables");
if (init_dumping(db))
DBUG_RETURN(1);
- /* Init hash table for storing the actual name of tables to dump */
- if (hash_init(&dump_tables, charset_info, 16, 0, 0,
- (hash_get_key) get_table_key, (hash_free_key) free_table_ent,
- 0))
+ init_alloc_root(&root, 8192, 0);
+ if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
exit(EX_EOM);
init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
for (; tables > 0 ; tables-- , table_names++)
{
/* the table name passed on commandline may be wrong case */
- if (!get_actual_table_name(*table_names,
- new_table_name, sizeof(new_table_name)))
+ if ((*pos= get_actual_table_name(*table_names, &root)))
{
/* Add found table name to lock_tables_query */
if (lock_tables)
{
- dynstr_append(&lock_tables_query,
- quote_name(new_table_name, table_buff, 1));
+ dynstr_append(&lock_tables_query, quote_name(*pos, table_buff, 1));
dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
}
-
- /* Add found table name to dump_tables list */
- if (my_hash_insert(&dump_tables,
- (byte*)my_strdup(new_table_name, MYF(0))))
- exit(EX_EOM);
-
+ pos++;
}
else
{
@@ -3156,6 +3144,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
/* We shall countinue here, if --force was given */
}
}
+ end= pos;
if (lock_tables)
{
@@ -3175,24 +3164,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
print_xml_tag1(md_result_file, "", "database name=", db, "\n");
/* Dump each selected table */
- for (i= 0; i < dump_tables.records; i++)
+ for (pos= dump_tables; pos < end; pos++)
{
- table_name= hash_element(&dump_tables, i);
- DBUG_PRINT("info",("Dumping table %s", table_name));
- dump_table(table_name,db);
+ DBUG_PRINT("info",("Dumping table %s", *pos));
+ dump_table(*pos, db);
if (opt_dump_triggers &&
mysql_get_server_version(sock) >= 50009)
- dump_triggers_for_table(table_name, db);
+ dump_triggers_for_table(*pos, db);
}
/* Dump each selected view */
if (was_views)
{
- for(i=0; i < dump_tables.records; i++)
- {
- table_name= hash_element(&dump_tables, i);
- get_view_structure(table_name, db);
- }
+ for (pos= dump_tables; pos < end; pos++)
+ get_view_structure(*pos, db);
}
if (opt_events && !opt_xml &&
mysql_get_server_version(sock) >= 50106)
@@ -3207,7 +3192,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
DBUG_PRINT("info", ("Dumping routines for database %s", db));
dump_routines_for_db(db);
}
- hash_free(&dump_tables);
+ free_root(&root, MYF(0));
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
order_by= 0;
if (opt_xml)
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 58afa434c0d..fe1f419214e 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -2757,6 +2757,9 @@ int do_connect(struct st_query *q)
#ifdef HAVE_OPENSSL
if (opt_use_ssl || con_ssl)
{
+ /* Turn on ssl_verify_server_cert only if host is "localhost" */
+ opt_ssl_verify_server_cert= !strcmp(con_host, "localhost");
+
mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4
index a2f70071e2d..3ed64b5625b 100644
--- a/config/ac-macros/misc.m4
+++ b/config/ac-macros/misc.m4
@@ -155,84 +155,6 @@ fi
])
-#---START: Used in for client configure
-AC_DEFUN([MYSQL_CHECK_ULONG],
-[AC_MSG_CHECKING(for type ulong)
-AC_CACHE_VAL(ac_cv_ulong,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- ulong foo;
- foo++;
- exit(0);
-}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
-AC_MSG_RESULT($ac_cv_ulong)
-if test "$ac_cv_ulong" = "yes"
-then
- AC_DEFINE([HAVE_ULONG], [1], [system headers define ulong])
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_UCHAR],
-[AC_MSG_CHECKING(for type uchar)
-AC_CACHE_VAL(ac_cv_uchar,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- uchar foo;
- foo++;
- exit(0);
-}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
-AC_MSG_RESULT($ac_cv_uchar)
-if test "$ac_cv_uchar" = "yes"
-then
- AC_DEFINE([HAVE_UCHAR], [1], [system headers define uchar])
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_UINT],
-[AC_MSG_CHECKING(for type uint)
-AC_CACHE_VAL(ac_cv_uint,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- uint foo;
- foo++;
- exit(0);
-}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
-AC_MSG_RESULT($ac_cv_uint)
-if test "$ac_cv_uint" = "yes"
-then
- AC_DEFINE([HAVE_UINT], [1], [system headers define uint])
-fi
-])
-
-
-AC_DEFUN([MYSQL_CHECK_IN_ADDR_T],
-[AC_MSG_CHECKING(for type in_addr_t)
-AC_CACHE_VAL(ac_cv_in_addr_t,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-int main(int argc, char **argv)
-{
- in_addr_t foo;
- exit(0);
-}], ac_cv_in_addr_t=yes, ac_cv_in_addr_t=no, ac_cv_in_addr_t=no)])
-AC_MSG_RESULT($ac_cv_in_addr_t)
-if test "$ac_cv_in_addr_t" = "yes"
-then
- AC_DEFINE([HAVE_IN_ADDR_T], [1], [system headers define in_addr_t])
-fi
-])
-
-
AC_DEFUN([MYSQL_PTHREAD_YIELD],
[AC_CACHE_CHECK([if pthread_yield takes zero arguments], ac_cv_pthread_yield_zero_arg,
[AC_TRY_LINK([#define _GNU_SOURCE
@@ -272,25 +194,6 @@ fi
#---END:
-AC_DEFUN([MYSQL_CHECK_FP_EXCEPT],
-[AC_MSG_CHECKING(for type fp_except)
-AC_CACHE_VAL(ac_cv_fp_except,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-#include <ieeefp.h>
-main()
-{
- fp_except foo;
- foo++;
- exit(0);
-}], ac_cv_fp_except=yes, ac_cv_fp_except=no, ac_cv_fp_except=no)])
-AC_MSG_RESULT($ac_cv_fp_except)
-if test "$ac_cv_fp_except" = "yes"
-then
- AC_DEFINE([HAVE_FP_EXCEPT], [1], [fp_except from ieeefp.h])
-fi
-])
-
# From fileutils-3.14/aclocal.m4
# @defmac AC_PROG_CC_STDC
diff --git a/config/ac-macros/ssl.m4 b/config/ac-macros/ssl.m4
index eec646462ea..0f2f207c36f 100644
--- a/config/ac-macros/ssl.m4
+++ b/config/ac-macros/ssl.m4
@@ -174,6 +174,16 @@ AC_MSG_CHECKING(for SSL)
[mysql_ssl_dir="$withval"],
[mysql_ssl_dir=no])
+ if test "$with_yassl"
+ then
+ AC_MSG_ERROR([The flag --with-yassl is deprecated, use --with-ssl])
+ fi
+
+ if test "$with_openssl"
+ then
+ AC_MSG_ERROR([The flag --with-openssl is deprecated, use --with-ssl])
+ fi
+
case "$mysql_ssl_dir" in
"no")
#
diff --git a/configure.in b/configure.in
index 95d78faf287..be6f3c8eaec 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 5.1.11-beta)
+AM_INIT_AUTOMAKE(mysql, 5.1.12-beta)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -778,48 +778,6 @@ struct request_info *req;
AC_SUBST(WRAPLIBS)
if test "$TARGET_LINUX" = "true"; then
- AC_MSG_CHECKING([for atomic operations])
-
- AC_LANG_SAVE
- AC_LANG_CPLUSPLUS
-
- atom_ops=
- AC_TRY_RUN([
-#include <asm/atomic.h>
-int main()
-{
- atomic_t v;
-
- atomic_set(&v, 23);
- atomic_add(5, &v);
- return atomic_read(&v) == 28 ? 0 : -1;
-}
- ],
- [AC_DEFINE([HAVE_ATOMIC_ADD], [1],
- [atomic_add() from <asm/atomic.h> (Linux only)])
- atom_ops="${atom_ops}atomic_add "],
- )
- AC_TRY_RUN([
-#include <asm/atomic.h>
-int main()
-{
- atomic_t v;
-
- atomic_set(&v, 23);
- atomic_sub(5, &v);
- return atomic_read(&v) == 18 ? 0 : -1;
-}
- ],
- [AC_DEFINE([HAVE_ATOMIC_SUB], [1],
- [atomic_sub() from <asm/atomic.h> (Linux only)])
- atom_ops="${atom_ops}atomic_sub "],
- )
-
- if test -z "$atom_ops"; then atom_ops="no"; fi
- AC_MSG_RESULT($atom_ops)
-
- AC_LANG_RESTORE
-
AC_ARG_WITH(pstack,
[ --with-pstack Use the pstack backtrace library],
[ USE_PSTACK=$withval ],
@@ -871,38 +829,20 @@ fi
# Later in this script LIBS will be augmented with a threads library.
NON_THREADED_LIBS="$LIBS"
-AC_MSG_CHECKING([for int8])
-case $SYSTEM_TYPE in
- *netware)
- AC_MSG_RESULT([no])
- ;;
- *)
-AC_TRY_RUN([
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_STDDEF_H
-#include <stddef.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
+AC_CHECK_TYPES([int8, uint8, int16, uint16, int32, uint32, int64, uint64,
+ uchar, uint, ulong],[],[], [
#include <sys/types.h>
-#endif
-
-int main()
-{
- int8 i;
- return 0;
-}
-],
-[AC_DEFINE([HAVE_INT_8_16_32], [1],
- [whether int8, int16 and int32 types exist])
-AC_MSG_RESULT([yes])],
-[AC_MSG_RESULT([no])]
-)
- ;;
-esac
+])
+AC_CHECK_TYPES([in_addr_t], [], [], [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+])
+AC_CHECK_TYPES([fp_except], [], [], [
+#include <sys/types.h>
+#include <ieeefp.h>
+])
#
# Some system specific hacks
@@ -1087,7 +1027,7 @@ dnl Is this the right match for DEC OSF on alpha?
# Edit Makefile.in files.
#
echo -n "configuring Makefile.in files for NetWare... "
- for file in sql/Makefile.in libmysql/Makefile.in libmysql_r/Makefile.in sql/share/Makefile.in strings/Makefile.in client/Makefile.in
+ for file in sql/Makefile.in extra/Makefile.in client/Makefile.in
do
# echo "#### $file ####"
filedir="`dirname $file`"
@@ -1108,32 +1048,13 @@ dnl Is this the right match for DEC OSF on alpha?
# Add library dependencies to mysqld_DEPENDENCIES
lib_DEPENDENCIES="\$(pstack_libs) \$(openssl_libs) \$(yassl_libs)"
cat > $filesed << EOF
-s,\(^.*\$(MAKE) gen_lex_hash\)\$(EXEEXT),#\1,
s,\(\./gen_lex_hash\)\$(EXEEXT),\1.linux,
-s%\(mysqld_DEPENDENCIES = \) %\1$lib_DEPENDENCIES %
-EOF
- ;;
- sql/share/Makefile.in)
- cat > $filesed << EOF
-s,\(extra/comp_err\),\1.linux,
+s%\(mysqld_DEPENDENCIES = \)%\1$lib_DEPENDENCIES %
EOF
;;
- libmysql/Makefile.in)
+ extra/Makefile.in)
cat > $filesed << EOF
-s,\(\./conf_to_src\)\( \$(top_srcdir)\),\1.linux\2,
-s,\(: conf_to_src\),\1.linux,
-EOF
- ;;
- libmysql_r/Makefile.in)
- cat > $filesed << EOF
-s,\(\./conf_to_src\)\( \$(top_srcdir)\),\1.linux\2,
-s,\(: conf_to_src\),\1.linux,
-EOF
- ;;
- strings/Makefile.in)
- cat > $filesed << EOF
-s,\(\./conf_to_src\)\( \$(top_srcdir)\),\1.linux\2,
-s,\(: conf_to_src\),\1.linux,
+s,\(extra/comp_err\)\$(EXEEXT),\1.linux,
EOF
;;
client/Makefile.in)
@@ -1650,6 +1571,20 @@ then
fi
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])
+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_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
+esac
+
# Force static compilation to avoid linking problems/get more speed
AC_ARG_WITH(mysqld-ldflags,
[ --with-mysqld-ldflags Extra linking arguments for mysqld],
@@ -1781,16 +1716,6 @@ MYSQL_FUNC_ALLOCA
MYSQL_TIMESPEC_TS
# Do we have the tzname variable
MYSQL_TZNAME
-# Do the system files define ulong
-MYSQL_CHECK_ULONG
-# Do the system files define uchar
-MYSQL_CHECK_UCHAR
-# Do the system files define uint
-MYSQL_CHECK_UINT
-# Check for fp_except in ieeefp.h
-MYSQL_CHECK_FP_EXCEPT
-# Check for IN_ADDR_T
-MYSQL_CHECK_IN_ADDR_T
# Do the c++ compiler have a bool type
MYSQL_CXX_BOOL
# Check some common bugs with gcc 2.8.# on sparc
diff --git a/extra/yassl/CMakeLists.txt b/extra/yassl/CMakeLists.txt
index cafa3011e94..e5429876072 100644
--- a/extra/yassl/CMakeLists.txt
+++ b/extra/yassl/CMakeLists.txt
@@ -1,4 +1,4 @@
-ADD_DEFINITIONS("-DWIN32 -D_LIB")
+ADD_DEFINITIONS("-DWIN32 -D_LIB -DYASSL_PREFIX")
INCLUDE_DIRECTORIES(include taocrypt/include mySTL)
ADD_LIBRARY(yassl src/buffer.cpp src/cert_wrapper.cpp src/crypto_wrapper.cpp src/handshake.cpp src/lock.cpp
diff --git a/extra/yassl/examples/echoserver/echoserver.cpp b/extra/yassl/examples/echoserver/echoserver.cpp
index 3243cc21a7c..8e23ead20ab 100644
--- a/extra/yassl/examples/echoserver/echoserver.cpp
+++ b/extra/yassl/examples/echoserver/echoserver.cpp
@@ -65,7 +65,8 @@ THREAD_RETURN YASSL_API echoserver_test(void* args)
while (!shutdown) {
sockaddr_in client;
socklen_t client_len = sizeof(client);
- int clientfd = accept(sockfd, (sockaddr*)&client, &client_len);
+ int clientfd = accept(sockfd, (sockaddr*)&client,
+ (ACCEPT_THIRD_T)&client_len);
if (clientfd == -1) err_sys("tcp accept failed");
SSL* ssl = SSL_new(ctx);
diff --git a/extra/yassl/include/openssl/crypto.h b/extra/yassl/include/openssl/crypto.h
index 4a0c1db0df1..288990e1318 100644
--- a/extra/yassl/include/openssl/crypto.h
+++ b/extra/yassl/include/openssl/crypto.h
@@ -3,6 +3,10 @@
#ifndef ysSSL_crypto_h__
#define yaSSL_crypto_h__
+#ifdef YASSL_PREFIX
+#include "prefix_crypto.h"
+#endif
+
const char* SSLeay_version(int type);
#define SSLEAY_VERSION 0x0900L
diff --git a/extra/yassl/include/openssl/generate_prefix_files.pl b/extra/yassl/include/openssl/generate_prefix_files.pl
new file mode 100755
index 00000000000..b921ee11e9a
--- /dev/null
+++ b/extra/yassl/include/openssl/generate_prefix_files.pl
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+#
+# This script generates defines for all functions
+# in yassl/include/openssl/ so they are renamed to
+# ya<old_function_name>. Hopefully that is unique enough.
+#
+# The script is to be run manually when we import
+# a new version of yaSSL
+#
+
+
+
+# Find all functions in "input" and add macros
+# to prefix/rename them into "output
+sub generate_prefix($$)
+{
+ my $input= shift;
+ my $output= shift;
+ open(IN, $input)
+ or die("Can't open input file $input: $!");
+ open(OUT, ">", $output)
+ or mtr_error("Can't open output file $output: $!");
+
+ while (<IN>)
+ {
+ chomp;
+
+ if ( /typedef/ )
+ {
+ next;
+ }
+
+ if ( /^\s*[a-zA-Z0-9*_ ]+\s+([_a-zA-Z0-9]+)\s*\(/ )
+ {
+ print OUT "#define $1 ya$1\n";
+ }
+ }
+
+ close OUT;
+ close IN;
+}
+
+generate_prefix("ssl.h", "prefix_ssl.h");
+generate_prefix("crypto.h", "prefix_crypto.h");
+
diff --git a/extra/yassl/include/openssl/prefix_crypto.h b/extra/yassl/include/openssl/prefix_crypto.h
new file mode 100644
index 00000000000..3fa5f32c627
--- /dev/null
+++ b/extra/yassl/include/openssl/prefix_crypto.h
@@ -0,0 +1 @@
+#define SSLeay_version yaSSLeay_version
diff --git a/extra/yassl/include/openssl/prefix_ssl.h b/extra/yassl/include/openssl/prefix_ssl.h
new file mode 100644
index 00000000000..7f815156f47
--- /dev/null
+++ b/extra/yassl/include/openssl/prefix_ssl.h
@@ -0,0 +1,152 @@
+#define Copyright yaCopyright
+#define yaSSL_CleanUp yayaSSL_CleanUp
+#define DH_new yaDH_new
+#define DH_free yaDH_free
+#define RSA_free yaRSA_free
+#define RSA_generate_key yaRSA_generate_key
+#define X509_free yaX509_free
+#define X509_STORE_CTX_get_current_cert yaX509_STORE_CTX_get_current_cert
+#define X509_STORE_CTX_get_error yaX509_STORE_CTX_get_error
+#define X509_STORE_CTX_get_error_depth yaX509_STORE_CTX_get_error_depth
+#define X509_NAME_oneline yaX509_NAME_oneline
+#define X509_get_issuer_name yaX509_get_issuer_name
+#define X509_get_subject_name yaX509_get_subject_name
+#define X509_verify_cert_error_string yaX509_verify_cert_error_string
+#define X509_LOOKUP_add_dir yaX509_LOOKUP_add_dir
+#define X509_LOOKUP_load_file yaX509_LOOKUP_load_file
+#define X509_LOOKUP_hash_dir yaX509_LOOKUP_hash_dir
+#define X509_LOOKUP_file yaX509_LOOKUP_file
+#define X509_STORE_add_lookup yaX509_STORE_add_lookup
+#define X509_STORE_new yaX509_STORE_new
+#define X509_STORE_get_by_subject yaX509_STORE_get_by_subject
+#define ERR_get_error_line_data yaERR_get_error_line_data
+#define ERR_print_errors_fp yaERR_print_errors_fp
+#define ERR_error_string yaERR_error_string
+#define ERR_remove_state yaERR_remove_state
+#define ERR_get_error yaERR_get_error
+#define ERR_peek_error yaERR_peek_error
+#define ERR_GET_REASON yaERR_GET_REASON
+#define SSL_CTX_new yaSSL_CTX_new
+#define SSL_new yaSSL_new
+#define SSL_set_fd yaSSL_set_fd
+#define SSL_connect yaSSL_connect
+#define SSL_write yaSSL_write
+#define SSL_read yaSSL_read
+#define SSL_accept yaSSL_accept
+#define SSL_CTX_free yaSSL_CTX_free
+#define SSL_free yaSSL_free
+#define SSL_clear yaSSL_clear
+#define SSL_shutdown yaSSL_shutdown
+#define SSL_set_connect_state yaSSL_set_connect_state
+#define SSL_set_accept_state yaSSL_set_accept_state
+#define SSL_do_handshake yaSSL_do_handshake
+#define SSL_get_cipher yaSSL_get_cipher
+#define SSL_get_cipher_name yaSSL_get_cipher_name
+#define SSL_get_shared_ciphers yaSSL_get_shared_ciphers
+#define SSL_get_cipher_list yaSSL_get_cipher_list
+#define SSL_get_version yaSSL_get_version
+#define SSLeay_version yaSSLeay_version
+#define SSL_get_error yaSSL_get_error
+#define SSL_load_error_strings yaSSL_load_error_strings
+#define SSL_set_session yaSSL_set_session
+#define SSL_get_session yaSSL_get_session
+#define SSL_SESSION_set_timeout yaSSL_SESSION_set_timeout
+#define SSL_get_peer_certificate yaSSL_get_peer_certificate
+#define SSL_get_verify_result yaSSL_get_verify_result
+#define SSL_CTX_set_verify yaSSL_CTX_set_verify
+#define SSL_CTX_load_verify_locations yaSSL_CTX_load_verify_locations
+#define SSL_CTX_set_default_verify_paths yaSSL_CTX_set_default_verify_paths
+#define SSL_CTX_check_private_key yaSSL_CTX_check_private_key
+#define SSL_CTX_set_session_id_context yaSSL_CTX_set_session_id_context
+#define SSL_CTX_set_tmp_rsa_callback yaSSL_CTX_set_tmp_rsa_callback
+#define SSL_CTX_set_options yaSSL_CTX_set_options
+#define SSL_CTX_set_session_cache_mode yaSSL_CTX_set_session_cache_mode
+#define SSL_CTX_set_timeout yaSSL_CTX_set_timeout
+#define SSL_CTX_use_certificate_chain_file yaSSL_CTX_use_certificate_chain_file
+#define SSL_CTX_set_default_passwd_cb yaSSL_CTX_set_default_passwd_cb
+#define SSL_CTX_use_RSAPrivateKey_file yaSSL_CTX_use_RSAPrivateKey_file
+#define SSL_CTX_set_info_callback yaSSL_CTX_set_info_callback
+#define SSL_CTX_sess_accept yaSSL_CTX_sess_accept
+#define SSL_CTX_sess_connect yaSSL_CTX_sess_connect
+#define SSL_CTX_sess_accept_good yaSSL_CTX_sess_accept_good
+#define SSL_CTX_sess_connect_good yaSSL_CTX_sess_connect_good
+#define SSL_CTX_sess_accept_renegotiate yaSSL_CTX_sess_accept_renegotiate
+#define SSL_CTX_sess_connect_renegotiate yaSSL_CTX_sess_connect_renegotiate
+#define SSL_CTX_sess_hits yaSSL_CTX_sess_hits
+#define SSL_CTX_sess_cb_hits yaSSL_CTX_sess_cb_hits
+#define SSL_CTX_sess_cache_full yaSSL_CTX_sess_cache_full
+#define SSL_CTX_sess_misses yaSSL_CTX_sess_misses
+#define SSL_CTX_sess_timeouts yaSSL_CTX_sess_timeouts
+#define SSL_CTX_sess_number yaSSL_CTX_sess_number
+#define SSL_CTX_sess_get_cache_size yaSSL_CTX_sess_get_cache_size
+#define SSL_CTX_get_verify_mode yaSSL_CTX_get_verify_mode
+#define SSL_get_verify_mode yaSSL_get_verify_mode
+#define SSL_CTX_get_verify_depth yaSSL_CTX_get_verify_depth
+#define SSL_get_verify_depth yaSSL_get_verify_depth
+#define SSL_get_default_timeout yaSSL_get_default_timeout
+#define SSL_CTX_get_session_cache_mode yaSSL_CTX_get_session_cache_mode
+#define SSL_session_reused yaSSL_session_reused
+#define SSL_set_rfd yaSSL_set_rfd
+#define SSL_set_wfd yaSSL_set_wfd
+#define SSL_set_shutdown yaSSL_set_shutdown
+#define SSL_want_read yaSSL_want_read
+#define SSL_want_write yaSSL_want_write
+#define SSL_pending yaSSL_pending
+#define SSL_CTX_use_certificate_file yaSSL_CTX_use_certificate_file
+#define SSL_CTX_use_PrivateKey_file yaSSL_CTX_use_PrivateKey_file
+#define SSL_CTX_set_cipher_list yaSSL_CTX_set_cipher_list
+#define SSL_CTX_sess_set_cache_size yaSSL_CTX_sess_set_cache_size
+#define SSL_CTX_set_tmp_dh yaSSL_CTX_set_tmp_dh
+#define OpenSSL_add_all_algorithms yaOpenSSL_add_all_algorithms
+#define SSL_library_init yaSSL_library_init
+#define SSLeay_add_ssl_algorithms yaSSLeay_add_ssl_algorithms
+#define SSL_get_current_cipher yaSSL_get_current_cipher
+#define SSL_CIPHER_description yaSSL_CIPHER_description
+#define SSL_alert_type_string_long yaSSL_alert_type_string_long
+#define SSL_alert_desc_string_long yaSSL_alert_desc_string_long
+#define SSL_state_string_long yaSSL_state_string_long
+#define EVP_md5 yaEVP_md5
+#define EVP_des_ede3_cbc yaEVP_des_ede3_cbc
+#define EVP_BytesToKey yaEVP_BytesToKey
+#define DES_set_key_unchecked yaDES_set_key_unchecked
+#define DES_ede3_cbc_encrypt yaDES_ede3_cbc_encrypt
+#define RAND_screen yaRAND_screen
+#define RAND_file_name yaRAND_file_name
+#define RAND_write_file yaRAND_write_file
+#define RAND_load_file yaRAND_load_file
+#define RAND_status yaRAND_status
+#define DES_set_key yaDES_set_key
+#define DES_set_odd_parity yaDES_set_odd_parity
+#define DES_ecb_encrypt yaDES_ecb_encrypt
+#define SSL_CTX_set_default_passwd_cb_userdata yaSSL_CTX_set_default_passwd_cb_userdata
+#define SSL_SESSION_free yaSSL_SESSION_free
+#define SSL_get_certificate yaSSL_get_certificate
+#define SSL_get_privatekey yaSSL_get_privatekey
+#define X509_get_pubkey yaX509_get_pubkey
+#define EVP_PKEY_copy_parameters yaEVP_PKEY_copy_parameters
+#define EVP_PKEY_free yaEVP_PKEY_free
+#define ERR_error_string_n yaERR_error_string_n
+#define ERR_free_strings yaERR_free_strings
+#define EVP_cleanup yaEVP_cleanup
+#define X509_get_ext_d2i yaX509_get_ext_d2i
+#define GENERAL_NAMES_free yaGENERAL_NAMES_free
+#define sk_GENERAL_NAME_num yask_GENERAL_NAME_num
+#define sk_GENERAL_NAME_value yask_GENERAL_NAME_value
+#define ASN1_STRING_data yaASN1_STRING_data
+#define ASN1_STRING_length yaASN1_STRING_length
+#define ASN1_STRING_type yaASN1_STRING_type
+#define X509_NAME_get_index_by_NID yaX509_NAME_get_index_by_NID
+#define X509_NAME_ENTRY_get_data yaX509_NAME_ENTRY_get_data
+#define X509_NAME_get_entry yaX509_NAME_get_entry
+#define ASN1_STRING_to_UTF8 yaASN1_STRING_to_UTF8
+#define SSLv23_client_method yaSSLv23_client_method
+#define SSLv2_client_method yaSSLv2_client_method
+#define SSL_get1_session yaSSL_get1_session
+#define X509_get_notBefore yaX509_get_notBefore
+#define X509_get_notAfter yaX509_get_notAfter
+#define MD4_Init yaMD4_Init
+#define MD4_Update yaMD4_Update
+#define MD4_Final yaMD4_Final
+#define MD5_Init yaMD5_Init
+#define MD5_Update yaMD5_Update
+#define MD5_Final yaMD5_Final
diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h
index a7eca9138a2..af801029561 100644
--- a/extra/yassl/include/openssl/ssl.h
+++ b/extra/yassl/include/openssl/ssl.h
@@ -28,6 +28,10 @@
#ifndef yaSSL_openssl_h__
#define yaSSL_openssl_h__
+#ifdef YASSL_PREFIX
+#include "prefix_ssl.h"
+#endif
+
#include <stdio.h> /* ERR_print fp */
#include "opensslv.h" /* for version number */
#include "rsa.h"
@@ -273,6 +277,7 @@ int SSL_pending(SSL*);
enum { /* ssl Constants */
+ SSL_WOULD_BLOCK = -8,
SSL_BAD_STAT = -7,
SSL_BAD_PATH = -6,
SSL_BAD_FILETYPE = -5,
@@ -372,11 +377,9 @@ char* SSL_state_string_long(SSL*);
/* EVP stuff, des and md5, different file? */
-typedef struct Digest Digest;
-typedef Digest EVP_MD;
+typedef char EVP_MD;
-typedef struct BulkCipher BulkCipher;
-typedef BulkCipher EVP_CIPHER;
+typedef char EVP_CIPHER;
typedef struct EVP_PKEY EVP_PKEY;
@@ -494,7 +497,7 @@ ASN1_TIME* X509_get_notAfter(X509* x);
typedef struct MD4_CTX {
- void* ptr;
+ int buffer[32]; /* big enough to hold, check size in Init */
} MD4_CTX;
void MD4_Init(MD4_CTX*);
diff --git a/extra/yassl/include/socket_wrapper.hpp b/extra/yassl/include/socket_wrapper.hpp
index d2258a93723..16db142b3a2 100644
--- a/extra/yassl/include/socket_wrapper.hpp
+++ b/extra/yassl/include/socket_wrapper.hpp
@@ -66,6 +66,7 @@ typedef unsigned char byte;
// Wraps Windows Sockets and BSD Sockets
class Socket {
socket_t socket_; // underlying socket descriptor
+ bool wouldBlock_; // for non-blocking data
public:
explicit Socket(socket_t s = INVALID_SOCKET);
~Socket();
@@ -75,9 +76,10 @@ public:
socket_t get_fd() const;
uint send(const byte* buf, unsigned int len, int flags = 0) const;
- uint receive(byte* buf, unsigned int len, int flags = 0) const;
+ uint receive(byte* buf, unsigned int len, int flags = 0);
- bool wait() const;
+ bool wait();
+ bool WouldBlock() const;
void closeSocket();
void shutDown(int how = SD_SEND);
diff --git a/extra/yassl/include/yassl_error.hpp b/extra/yassl/include/yassl_error.hpp
index 9c12b06e34a..2f35fecb59b 100644
--- a/extra/yassl/include/yassl_error.hpp
+++ b/extra/yassl/include/yassl_error.hpp
@@ -26,7 +26,6 @@
#ifndef yaSSL_ERROR_HPP
#define yaSSL_ERROR_HPP
-#include "stdexcept.hpp"
namespace yaSSL {
@@ -63,7 +62,7 @@ enum { MAX_ERROR_SZ = 80 };
void SetErrorString(YasslError, char*);
-
+/* remove for now, if go back to exceptions use this wrapper
// Base class for all yaSSL exceptions
class Error : public mySTL::runtime_error {
YasslError error_;
@@ -75,6 +74,7 @@ public:
YasslError get_number() const;
Library get_lib() const;
};
+*/
} // naemspace
diff --git a/extra/yassl/include/yassl_int.hpp b/extra/yassl/include/yassl_int.hpp
index 97ae468d2f9..633b75d479f 100644
--- a/extra/yassl/include/yassl_int.hpp
+++ b/extra/yassl/include/yassl_int.hpp
@@ -127,25 +127,6 @@ private:
};
-// hold add crypt references provided to callers
-class CryptProvider {
- mySTL::list<Digest*> digestList_;
- mySTL::list<BulkCipher*> cipherList_;
- CryptProvider() {} // only GetCryptProvider creates
-public:
- ~CryptProvider();
-
- Digest* NewMd5();
- BulkCipher* NewDesEde();
-
- friend CryptProvider& GetCryptProvider();
-private:
- CryptProvider(const CryptProvider&); // hide copy
- CryptProvider& operator=(const CryptProvider&); // and assign
-};
-
-CryptProvider& GetCryptProvider();
-
#undef X509_NAME // wincrypt.h clash
// openSSL X509 names
diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am
index a852ca4019b..2b3e1aea5f5 100644
--- a/extra/yassl/src/Makefile.am
+++ b/extra/yassl/src/Makefile.am
@@ -5,4 +5,4 @@ libyassl_la_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \
handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \
template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp
EXTRA_DIST = $(wildcard ../include/*.hpp) $(wildcard ../include/openssl/*.h)
-AM_CXXFLAGS = -DYASSL_PURE_C
+AM_CXXFLAGS = -DYASSL_PURE_C -DYASSL_PREFIX
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 2603365e41a..2b099af930c 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -656,7 +656,7 @@ mySTL::auto_ptr<input_buffer>
DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered)
{
// wait for input if blocking
- if (!ssl.getSocket().wait()) {
+ if (!ssl.useSocket().wait()) {
ssl.SetError(receive_error);
buffered.reset(0);
return buffered;
@@ -673,7 +673,7 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered)
}
// add new data
- uint read = ssl.getSocket().receive(buffer.get_buffer() + buffSz, ready);
+ uint read = ssl.useSocket().receive(buffer.get_buffer() + buffSz, ready);
buffer.add_size(read);
uint offset = 0;
const MessageFactory& mf = ssl.getFactory().getMessage();
@@ -858,6 +858,9 @@ void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer)
// send data
int sendData(SSL& ssl, const void* buffer, int sz)
{
+ if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ))
+ ssl.SetError(no_error);
+
ssl.verfiyHandShakeComplete();
if (ssl.GetError()) return 0;
int sent = 0;
@@ -893,6 +896,9 @@ int sendAlert(SSL& ssl, const Alert& alert)
// process input data
int receiveData(SSL& ssl, Data& data)
{
+ if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ))
+ ssl.SetError(no_error);
+
ssl.verfiyHandShakeComplete();
if (ssl.GetError()) return 0;
@@ -902,6 +908,11 @@ int receiveData(SSL& ssl, Data& data)
ssl.useLog().ShowData(data.get_length());
if (ssl.GetError()) return 0;
+
+ if (data.get_length() == 0 && ssl.getSocket().WouldBlock()) {
+ ssl.SetError(YasslError(SSL_ERROR_WANT_READ));
+ return SSL_WOULD_BLOCK;
+ }
return data.get_length();
}
diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp
index c6611803421..803f4b01249 100644
--- a/extra/yassl/src/socket_wrapper.cpp
+++ b/extra/yassl/src/socket_wrapper.cpp
@@ -58,7 +58,7 @@ namespace yaSSL {
Socket::Socket(socket_t s)
- : socket_(s)
+ : socket_(s), wouldBlock_(false)
{}
@@ -123,17 +123,21 @@ uint Socket::send(const byte* buf, unsigned int sz, int flags) const
}
-uint Socket::receive(byte* buf, unsigned int sz, int flags) const
+uint Socket::receive(byte* buf, unsigned int sz, int flags)
{
assert(socket_ != INVALID_SOCKET);
+ wouldBlock_ = false;
+
int recvd = ::recv(socket_, reinterpret_cast<char *>(buf), sz, flags);
// idea to seperate error from would block by arnetheduck@gmail.com
if (recvd == -1) {
if (get_lastError() == SOCKET_EWOULDBLOCK ||
- get_lastError() == SOCKET_EAGAIN)
+ get_lastError() == SOCKET_EAGAIN) {
+ wouldBlock_ = true;
return 0;
}
+ }
else if (recvd == 0)
return static_cast<uint>(-1);
@@ -142,7 +146,7 @@ uint Socket::receive(byte* buf, unsigned int sz, int flags) const
// wait if blocking for input, return false for error
-bool Socket::wait() const
+bool Socket::wait()
{
byte b;
return receive(&b, 1, MSG_PEEK) != static_cast<uint>(-1);
@@ -166,6 +170,12 @@ int Socket::get_lastError()
}
+bool Socket::WouldBlock() const
+{
+ return wouldBlock_;
+}
+
+
void Socket::set_lastError(int errorCode)
{
#ifdef _WIN32
diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp
index 66196514a87..07f5e9859b2 100644
--- a/extra/yassl/src/ssl.cpp
+++ b/extra/yassl/src/ssl.cpp
@@ -37,6 +37,7 @@
#include "handshake.hpp"
#include "yassl_int.hpp"
#include "md5.hpp" // for TaoCrypt MD5 size assert
+#include "md4.hpp" // for TaoCrypt MD4 size assert
#include <stdio.h>
#ifdef _WIN32
@@ -810,25 +811,34 @@ const char* X509_verify_cert_error_string(long /* error */)
const EVP_MD* EVP_md5(void)
{
- return GetCryptProvider().NewMd5();
+ static const char* type = "MD5";
+ return type;
}
const EVP_CIPHER* EVP_des_ede3_cbc(void)
{
- return GetCryptProvider().NewDesEde();
+ static const char* type = "DES_EDE3_CBC";
+ return type;
}
int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md, const byte* salt,
const byte* data, int sz, int count, byte* key, byte* iv)
{
- EVP_MD* myMD = const_cast<EVP_MD*>(md);
- uint digestSz = myMD->get_digestSize();
+ // only support MD5 for now
+ if (strncmp(md, "MD5", 3)) return 0;
+
+ // only support DES_EDE3_CBC for now
+ if (strncmp(type, "DES_EDE3_CBC", 12)) return 0;
+
+ yaSSL::MD5 myMD;
+ uint digestSz = myMD.get_digestSize();
byte digest[SHA_LEN]; // max size
- int keyLen = type->get_keySize();
- int ivLen = type->get_ivSize();
+ yaSSL::DES_EDE cipher;
+ int keyLen = cipher.get_keySize();
+ int ivLen = cipher.get_ivSize();
int keyLeft = keyLen;
int ivLeft = ivLen;
int keyOutput = 0;
@@ -837,17 +847,17 @@ int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md, const byte* salt,
int digestLeft = digestSz;
// D_(i - 1)
if (keyOutput) // first time D_0 is empty
- myMD->update(digest, digestSz);
+ myMD.update(digest, digestSz);
// data
- myMD->update(data, sz);
+ myMD.update(data, sz);
// salt
if (salt)
- myMD->update(salt, EVP_SALT_SZ);
- myMD->get_digest(digest);
+ myMD.update(salt, EVP_SALT_SZ);
+ myMD.get_digest(digest);
// count
for (int j = 1; j < count; j++) {
- myMD->update(digest, digestSz);
- myMD->get_digest(digest);
+ myMD.update(digest, digestSz);
+ myMD.get_digest(digest);
}
if (keyLeft) {
@@ -1131,17 +1141,26 @@ void* X509_get_ext_d2i(X509* x, int nid, int* crit, int* idx)
void MD4_Init(MD4_CTX* md4)
{
- assert(0); // not yet supported, build compat. only
+ // make sure we have a big enough buffer
+ typedef char ok[sizeof(md4->buffer) >= sizeof(TaoCrypt::MD4) ? 1 : -1];
+ (void) sizeof(ok);
+
+ // using TaoCrypt since no dynamic memory allocated
+ // and no destructor will be called
+ new (reinterpret_cast<yassl_pointer>(md4->buffer)) TaoCrypt::MD4();
}
void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz)
{
+ reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Update(
+ static_cast<const byte*>(data), static_cast<unsigned int>(sz));
}
void MD4_Final(unsigned char* hash, MD4_CTX* md4)
{
+ reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Final(hash);
}
diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp
index 43b80d59a4d..ce8972c72fe 100644
--- a/extra/yassl/src/template_instnt.cpp
+++ b/extra/yassl/src/template_instnt.cpp
@@ -31,6 +31,7 @@
#include "hmac.hpp"
#include "md5.hpp"
#include "sha.hpp"
+#include "ripemd.hpp"
#include "openssl/ssl.h"
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
@@ -85,7 +86,6 @@ template void ysDelete<X509>(X509*);
template void ysDelete<Message>(Message*);
template void ysDelete<sslFactory>(sslFactory*);
template void ysDelete<Sessions>(Sessions*);
-template void ysDelete<CryptProvider>(CryptProvider*);
template void ysArrayDelete<unsigned char>(unsigned char*);
template void ysArrayDelete<char>(char*);
}
diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp
index 4fe0d3aa4f9..8b7d2d17a84 100644
--- a/extra/yassl/src/timer.cpp
+++ b/extra/yassl/src/timer.cpp
@@ -26,13 +26,17 @@
#include "runtime.hpp"
#include "timer.hpp"
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
namespace yaSSL {
#ifdef _WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
-
timer_d timer()
{
static bool init(false);
@@ -57,8 +61,6 @@ namespace yaSSL {
#else // _WIN32
- #include <sys/time.h>
-
timer_d timer()
{
struct timeval tv;
diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp
index 59113d7438c..72b8e459241 100644
--- a/extra/yassl/src/yassl_error.cpp
+++ b/extra/yassl/src/yassl_error.cpp
@@ -26,10 +26,13 @@
#include "runtime.hpp"
#include "yassl_error.hpp"
#include "error.hpp" // TaoCrypt error numbers
+#include "openssl/ssl.h" // SSL_ERROR_WANT_READ
+#include <string.h> // strncpy
namespace yaSSL {
+/* may bring back in future
Error::Error(const char* s, YasslError e, Library l)
: mySTL::runtime_error(s), error_(e), lib_(l)
{
@@ -47,6 +50,7 @@ Library Error::get_lib() const
return lib_;
}
+*/
void SetErrorString(YasslError error, char* buffer)
@@ -117,6 +121,11 @@ void SetErrorString(YasslError error, char* buffer)
strncpy(buffer, "unable to proccess cerificate", max);
break;
+ // openssl errors
+ case SSL_ERROR_WANT_READ :
+ strncpy(buffer, "the read operation would block", max);
+ break;
+
// TaoCrypt errors
case NO_ERROR :
strncpy(buffer, "not in error state", max);
diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp
index f7fb1abfa3f..1ff46903bfd 100644
--- a/extra/yassl/src/yassl_int.cpp
+++ b/extra/yassl/src/yassl_int.cpp
@@ -1382,47 +1382,6 @@ sslFactory& GetSSL_Factory()
}
-static CryptProvider* cryptProviderInstance = 0;
-
-CryptProvider& GetCryptProvider()
-{
- if (!cryptProviderInstance)
- cryptProviderInstance = NEW_YS CryptProvider;
- return *cryptProviderInstance;
-}
-
-
-CryptProvider::~CryptProvider()
-{
- mySTL::for_each(digestList_.begin(), digestList_.end(), del_ptr_zero());
- mySTL::for_each(cipherList_.begin(), cipherList_.end(), del_ptr_zero());
-}
-
-
-Digest* CryptProvider::NewMd5()
-{
- Digest* ptr = NEW_YS MD5();
- digestList_.push_back(ptr);
- return ptr;
-}
-
-
-BulkCipher* CryptProvider::NewDesEde()
-{
- BulkCipher* ptr = NEW_YS DES_EDE();
- cipherList_.push_back(ptr);
- return ptr;
-}
-
-
-extern "C" void yaSSL_CleanUp()
-{
- TaoCrypt::CleanUp();
- ysDelete(cryptProviderInstance);
- ysDelete(sslFactoryInstance);
- ysDelete(sessionsInstance);
-}
-
typedef Mutex::Lock Lock;
@@ -2109,9 +2068,21 @@ ASN1_STRING* StringHolder::GetString()
}
-
} // namespace
+
+extern "C" void yaSSL_CleanUp()
+{
+ TaoCrypt::CleanUp();
+ yaSSL::ysDelete(yaSSL::sslFactoryInstance);
+ yaSSL::ysDelete(yaSSL::sessionsInstance);
+
+ // In case user calls more than once, prevent seg fault
+ yaSSL::sslFactoryInstance = 0;
+ yaSSL::sessionsInstance = 0;
+}
+
+
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace mySTL {
template yaSSL::yassl_int_cpp_local1::SumData for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData);
diff --git a/extra/yassl/taocrypt/CMakeLists.txt b/extra/yassl/taocrypt/CMakeLists.txt
index 3ad9195b372..0af0a242e5d 100644
--- a/extra/yassl/taocrypt/CMakeLists.txt
+++ b/extra/yassl/taocrypt/CMakeLists.txt
@@ -2,7 +2,7 @@ INCLUDE_DIRECTORIES(../mySTL include)
ADD_LIBRARY(taocrypt src/aes.cpp src/aestables.cpp src/algebra.cpp src/arc4.cpp src/asn.cpp src/coding.cpp
src/des.cpp src/dh.cpp src/dsa.cpp src/file.cpp src/hash.cpp src/integer.cpp src/md2.cpp
- src/md5.cpp src/misc.cpp src/random.cpp src/ripemd.cpp src/rsa.cpp src/sha.cpp
+ src/md4.cpp src/md5.cpp src/misc.cpp src/random.cpp src/ripemd.cpp src/rsa.cpp src/sha.cpp
include/aes.hpp include/algebra.hpp include/arc4.hpp include/asn.hpp include/block.hpp
include/coding.hpp include/des.hpp include/dh.hpp include/dsa.hpp include/dsa.hpp
include/error.hpp include/file.hpp include/hash.hpp include/hmac.hpp include/integer.hpp
diff --git a/extra/yassl/taocrypt/include/block.hpp b/extra/yassl/taocrypt/include/block.hpp
index 4c262e1a540..76836615ce6 100644
--- a/extra/yassl/taocrypt/include/block.hpp
+++ b/extra/yassl/taocrypt/include/block.hpp
@@ -96,7 +96,7 @@ public:
pointer allocate(size_type n, const void* = 0)
{
- CheckSize(n);
+ this->CheckSize(n);
if (n == 0)
return 0;
return NEW_TC T[n];
diff --git a/extra/yassl/taocrypt/include/md4.hpp b/extra/yassl/taocrypt/include/md4.hpp
new file mode 100644
index 00000000000..aac930d7498
--- /dev/null
+++ b/extra/yassl/taocrypt/include/md4.hpp
@@ -0,0 +1,65 @@
+/* md4.hpp
+ *
+ * Copyright (C) 2003 Sawtooth Consulting Ltd.
+ *
+ * This file is part of yaSSL.
+ *
+ * yaSSL 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.
+ *
+ * yaSSL 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
+ */
+
+/* md4.hpp provides MD4 digest support
+ * WANRING: MD4 is considered insecure, only use if you have to, e.g., yaSSL
+ * libcurl supports needs this for NTLM authentication
+*/
+
+#ifndef TAO_CRYPT_MD4_HPP
+#define TAO_CRYPT_MD4_HPP
+
+#include "hash.hpp"
+
+namespace TaoCrypt {
+
+
+// MD4 digest
+class MD4 : public HASHwithTransform {
+public:
+ enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56,
+ TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes
+ MD4() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE)
+ { Init(); }
+ ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); }
+ word32 getBlockSize() const { return BLOCK_SIZE; }
+ word32 getDigestSize() const { return DIGEST_SIZE; }
+ word32 getPadSize() const { return PAD_SIZE; }
+
+ MD4(const MD4&);
+ MD4& operator= (const MD4&);
+
+ void Init();
+ void Swap(MD4&);
+private:
+ void Transform();
+};
+
+inline void swap(MD4& a, MD4& b)
+{
+ a.Swap(b);
+}
+
+
+} // namespace
+
+#endif // TAO_CRYPT_MD4_HPP
+
diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp
index 09ca7524ef3..3a5cf62865a 100644
--- a/extra/yassl/taocrypt/include/runtime.hpp
+++ b/extra/yassl/taocrypt/include/runtime.hpp
@@ -28,10 +28,6 @@
#ifndef yaSSL_NEW_HPP
#define yaSSL_NEW_HPP
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#ifdef __sun
diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am
index d3e72346110..1110ed335b8 100644
--- a/extra/yassl/taocrypt/src/Makefile.am
+++ b/extra/yassl/taocrypt/src/Makefile.am
@@ -4,7 +4,7 @@ noinst_LTLIBRARIES = libtaocrypt.la
libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp \
asn.cpp bftables.cpp blowfish.cpp coding.cpp des.cpp dh.cpp \
- dsa.cpp file.cpp hash.cpp integer.cpp md2.cpp md5.cpp misc.cpp \
+ dsa.cpp file.cpp hash.cpp integer.cpp md2.cpp md4.cpp md5.cpp misc.cpp \
random.cpp ripemd.cpp rsa.cpp sha.cpp template_instnt.cpp \
tftables.cpp twofish.cpp
diff --git a/extra/yassl/taocrypt/src/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp
index 885ddfbf630..a296e122985 100644
--- a/extra/yassl/taocrypt/src/integer.cpp
+++ b/extra/yassl/taocrypt/src/integer.cpp
@@ -2735,8 +2735,11 @@ void CleanUp()
{
tcDelete(one);
tcDelete(zero);
-}
+ // In case user calls more than once, prevent seg fault
+ one = 0;
+ zero = 0;
+}
Integer::Integer(RandomNumberGenerator& rng, const Integer& min,
const Integer& max)
diff --git a/extra/yassl/taocrypt/src/md4.cpp b/extra/yassl/taocrypt/src/md4.cpp
new file mode 100644
index 00000000000..dfc2b079141
--- /dev/null
+++ b/extra/yassl/taocrypt/src/md4.cpp
@@ -0,0 +1,154 @@
+/* md4.cpp
+ *
+ * Copyright (C) 2003 Sawtooth Consulting Ltd.
+ *
+ * This file is part of yaSSL.
+ *
+ * yaSSL 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.
+ *
+ * yaSSL 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
+ */
+
+
+/* based on Wei Dai's md4.cpp from CryptoPP */
+
+#include "runtime.hpp"
+#include "md4.hpp"
+#include "algorithm.hpp" // mySTL::swap
+
+
+
+namespace TaoCrypt {
+
+void MD4::Init()
+{
+ digest_[0] = 0x67452301L;
+ digest_[1] = 0xefcdab89L;
+ digest_[2] = 0x98badcfeL;
+ digest_[3] = 0x10325476L;
+
+ buffLen_ = 0;
+ loLen_ = 0;
+ hiLen_ = 0;
+}
+
+
+MD4::MD4(const MD4& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32),
+ BLOCK_SIZE)
+{
+ buffLen_ = that.buffLen_;
+ loLen_ = that.loLen_;
+ hiLen_ = that.hiLen_;
+
+ memcpy(digest_, that.digest_, DIGEST_SIZE);
+ memcpy(buffer_, that.buffer_, BLOCK_SIZE);
+}
+
+MD4& MD4::operator= (const MD4& that)
+{
+ MD4 tmp(that);
+ Swap(tmp);
+
+ return *this;
+}
+
+
+void MD4::Swap(MD4& other)
+{
+ mySTL::swap(loLen_, other.loLen_);
+ mySTL::swap(hiLen_, other.hiLen_);
+ mySTL::swap(buffLen_, other.buffLen_);
+
+ memcpy(digest_, other.digest_, DIGEST_SIZE);
+ memcpy(buffer_, other.buffer_, BLOCK_SIZE);
+}
+
+
+void MD4::Transform()
+{
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+ word32 A, B, C, D;
+
+ A = digest_[0];
+ B = digest_[1];
+ C = digest_[2];
+ D = digest_[3];
+
+#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+buffer_[k],s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 1, 7);
+ function(C,D,A,B, 2,11);
+ function(B,C,D,A, 3,19);
+ function(A,B,C,D, 4, 3);
+ function(D,A,B,C, 5, 7);
+ function(C,D,A,B, 6,11);
+ function(B,C,D,A, 7,19);
+ function(A,B,C,D, 8, 3);
+ function(D,A,B,C, 9, 7);
+ function(C,D,A,B,10,11);
+ function(B,C,D,A,11,19);
+ function(A,B,C,D,12, 3);
+ function(D,A,B,C,13, 7);
+ function(C,D,A,B,14,11);
+ function(B,C,D,A,15,19);
+
+#undef function
+#define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+buffer_[k]+0x5a827999,s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 4, 5);
+ function(C,D,A,B, 8, 9);
+ function(B,C,D,A,12,13);
+ function(A,B,C,D, 1, 3);
+ function(D,A,B,C, 5, 5);
+ function(C,D,A,B, 9, 9);
+ function(B,C,D,A,13,13);
+ function(A,B,C,D, 2, 3);
+ function(D,A,B,C, 6, 5);
+ function(C,D,A,B,10, 9);
+ function(B,C,D,A,14,13);
+ function(A,B,C,D, 3, 3);
+ function(D,A,B,C, 7, 5);
+ function(C,D,A,B,11, 9);
+ function(B,C,D,A,15,13);
+
+#undef function
+#define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+buffer_[k]+0x6ed9eba1,s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 8, 9);
+ function(C,D,A,B, 4,11);
+ function(B,C,D,A,12,15);
+ function(A,B,C,D, 2, 3);
+ function(D,A,B,C,10, 9);
+ function(C,D,A,B, 6,11);
+ function(B,C,D,A,14,15);
+ function(A,B,C,D, 1, 3);
+ function(D,A,B,C, 9, 9);
+ function(C,D,A,B, 5,11);
+ function(B,C,D,A,13,15);
+ function(A,B,C,D, 3, 3);
+ function(D,A,B,C,11, 9);
+ function(C,D,A,B, 7,11);
+ function(B,C,D,A,15,15);
+
+ digest_[0] += A;
+ digest_[1] += B;
+ digest_[2] += C;
+ digest_[3] += D;
+}
+
+
+} // namespace
+
diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp
index 4ef163a7f5d..2869df71c8a 100644
--- a/extra/yassl/taocrypt/src/misc.cpp
+++ b/extra/yassl/taocrypt/src/misc.cpp
@@ -81,6 +81,19 @@ extern "C" {
}
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+
+extern "C" {
+
+ int __cxa_pure_virtual() {
+ assert("Pure virtual method called." == "Aborted");
+ return 0;
+ }
+
+} // extern "C"
+
+#endif
+
#endif // YASSL_PURE_C
diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp
index 5efd2d32a10..12bcd8238f2 100644
--- a/extra/yassl/taocrypt/src/template_instnt.cpp
+++ b/extra/yassl/taocrypt/src/template_instnt.cpp
@@ -30,11 +30,11 @@
#include "sha.hpp"
#include "md5.hpp"
#include "hmac.hpp"
+#include "ripemd.hpp"
#include "pwdbased.hpp"
#include "algebra.hpp"
#include "vector.hpp"
#include "hash.hpp"
-#include "ripemd.hpp"
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace TaoCrypt {
diff --git a/extra/yassl/taocrypt/taocrypt.dsp b/extra/yassl/taocrypt/taocrypt.dsp
index b741cef0096..19edf7b2f22 100644
--- a/extra/yassl/taocrypt/taocrypt.dsp
+++ b/extra/yassl/taocrypt/taocrypt.dsp
@@ -146,6 +146,10 @@ SOURCE=.\src\md2.cpp
# End Source File
# Begin Source File
+SOURCE=.\src\md4.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\src\md5.cpp
# End Source File
# Begin Source File
@@ -246,6 +250,10 @@ SOURCE=.\include\md2.hpp
# End Source File
# Begin Source File
+SOURCE=.\include\md4.hpp
+# End Source File
+# Begin Source File
+
SOURCE=.\include\md5.hpp
# End Source File
# Begin Source File
diff --git a/extra/yassl/taocrypt/taocrypt.vcproj b/extra/yassl/taocrypt/taocrypt.vcproj
index 603fafd4090..7eef7b82db7 100755
--- a/extra/yassl/taocrypt/taocrypt.vcproj
+++ b/extra/yassl/taocrypt/taocrypt.vcproj
@@ -397,6 +397,27 @@
</FileConfiguration>
</File>
<File
+ RelativePath="src\md4.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="src\md5.cpp">
<FileConfiguration
Name="Debug|Win32">
@@ -572,6 +593,9 @@
RelativePath="include\md2.hpp">
</File>
<File
+ RelativePath="include\md4.hpp">
+ </File>
+ <File
RelativePath="include\md5.hpp">
</File>
<File
diff --git a/extra/yassl/taocrypt/test/test.cpp b/extra/yassl/taocrypt/test/test.cpp
index b8618b18d47..28ef73dfac8 100644
--- a/extra/yassl/taocrypt/test/test.cpp
+++ b/extra/yassl/taocrypt/test/test.cpp
@@ -8,6 +8,7 @@
#include "sha.hpp"
#include "md5.hpp"
#include "md2.hpp"
+#include "md4.hpp"
#include "ripemd.hpp"
#include "hmac.hpp"
#include "arc4.hpp"
@@ -30,6 +31,7 @@ using TaoCrypt::word32;
using TaoCrypt::SHA;
using TaoCrypt::MD5;
using TaoCrypt::MD2;
+using TaoCrypt::MD4;
using TaoCrypt::RIPEMD160;
using TaoCrypt::HMAC;
using TaoCrypt::ARC4;
@@ -89,6 +91,7 @@ void file_test(int, char**);
int sha_test();
int md5_test();
int md2_test();
+int md4_test();
int ripemd_test();
int hmac_test();
int arc4_test();
@@ -165,6 +168,11 @@ void taocrypt_test(void* args)
else
printf( "MD2 test passed!\n");
+ if ( (ret = md4_test()) )
+ err_sys("MD4 test failed!\n", ret);
+ else
+ printf( "MD4 test passed!\n");
+
if ( (ret = ripemd_test()) )
err_sys("RIPEMD test failed!\n", ret);
else
@@ -348,6 +356,51 @@ int md5_test()
}
+int md4_test()
+{
+ MD4 md4;
+ byte hash[MD4::DIGEST_SIZE];
+
+ testVector test_md4[] =
+ {
+ testVector("",
+ "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89"
+ "\xc0"),
+ testVector("a",
+ "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb"
+ "\x24"),
+ testVector("abc",
+ "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72"
+ "\x9d"),
+ testVector("message digest",
+ "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01"
+ "\x4b"),
+ testVector("abcdefghijklmnopqrstuvwxyz",
+ "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d"
+ "\xa9"),
+ testVector("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345"
+ "6789",
+ "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0"
+ "\xe4"),
+ testVector("1234567890123456789012345678901234567890123456789012345678"
+ "9012345678901234567890",
+ "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05"
+ "\x36")
+ };
+
+ int times( sizeof(test_md4) / sizeof(testVector) );
+ for (int i = 0; i < times; ++i) {
+ md4.Update(test_md4[i].input_, test_md4[i].inLen_);
+ md4.Final(hash);
+
+ if (memcmp(hash, test_md4[i].output_, MD4::DIGEST_SIZE) != 0)
+ return -5 - i;
+ }
+
+ return 0;
+}
+
+
int md2_test()
{
MD2 md5;
diff --git a/extra/yassl/testsuite/Makefile.am b/extra/yassl/testsuite/Makefile.am
index d91822f609e..2ae46a1b409 100644
--- a/extra/yassl/testsuite/Makefile.am
+++ b/extra/yassl/testsuite/Makefile.am
@@ -5,7 +5,7 @@ testsuite_SOURCES = testsuite.cpp ../taocrypt/test/test.cpp \
../examples/echoclient/echoclient.cpp \
../examples/echoserver/echoserver.cpp
testsuite_LDFLAGS = -L../src/ -L../taocrypt/src
-testsuite_CXXFLAGS = -DYASSL_PURE_C -DNO_MAIN_DRIVER
+testsuite_CXXFLAGS = -DYASSL_PURE_C -DYASSL_PREFIX -DNO_MAIN_DRIVER
testsuite_LDADD = -lyassl -ltaocrypt
testsuite_DEPENDENCIES = ../src/libyassl.la ../taocrypt/src/libtaocrypt.la
EXTRA_DIST = testsuite.dsp test.hpp input quit make.bat
diff --git a/extra/yassl/testsuite/test.hpp b/extra/yassl/testsuite/test.hpp
index 259975fba0b..c80e3ad23da 100644
--- a/extra/yassl/testsuite/test.hpp
+++ b/extra/yassl/testsuite/test.hpp
@@ -33,10 +33,16 @@
// HPUX doesn't use socklent_t for third parameter to accept
-#if !defined(__hpux__)
+#if !defined(__hpux)
typedef socklen_t* ACCEPT_THIRD_T;
#else
typedef int* ACCEPT_THIRD_T;
+
+// HPUX does not define _POSIX_THREADS as it's not _fully_ implemented
+#ifndef _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
#endif
diff --git a/extra/yassl/yassl.vcproj b/extra/yassl/yassl.vcproj
index e2915e3f575..a7688ac4583 100755
--- a/extra/yassl/yassl.vcproj
+++ b/extra/yassl/yassl.vcproj
@@ -22,7 +22,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="include,taocrypt\include,mySTL"
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;YASSL_PREFIX"
ExceptionHandling="FALSE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -76,7 +76,7 @@
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="include,taocrypt\include,mySTL"
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;YASSL_PREFIX"
StringPooling="TRUE"
ExceptionHandling="FALSE"
RuntimeLibrary="0"
diff --git a/include/Makefile.am b/include/Makefile.am
index e1ddadb933a..27b359bb6a3 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -31,7 +31,8 @@ noinst_HEADERS = config-win.h config-netware.h \
my_aes.h my_tree.h my_trie.h hash.h thr_alarm.h \
thr_lock.h t_ctype.h violite.h md5.h base64.h \
mysql_version.h.in my_handler.h my_time.h decimal.h \
- my_vle.h my_user.h
+ my_vle.h my_user.h my_atomic.h atomic/nolock.h \
+ atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h
# mysql_version.h are generated
CLEANFILES = mysql_version.h my_config.h readline openssl
diff --git a/include/atomic/nolock.h b/include/atomic/nolock.h
new file mode 100644
index 00000000000..cf21a94c7de
--- /dev/null
+++ b/include/atomic/nolock.h
@@ -0,0 +1,169 @@
+/* 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 */
+
+#if defined(__i386__) || defined(_M_IX86)
+#ifdef MY_ATOMIC_MODE_DUMMY
+# define LOCK ""
+#else
+# define LOCK "lock "
+#endif
+#ifdef __GNUC__
+#include "x86-gcc.h"
+#elif defined(_MSC_VER)
+#include "x86-msvc.h"
+#endif
+#endif
+
+#ifdef make_atomic_add_body8
+
+#ifdef HAVE_INLINE
+
+#define make_atomic_add(S) \
+static inline uint ## S _my_atomic_add ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v) \
+{ \
+ make_atomic_add_body ## S; \
+ return v; \
+}
+
+#define make_atomic_swap(S) \
+static inline uint ## S _my_atomic_swap ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v) \
+{ \
+ make_atomic_swap_body ## S; \
+ return v; \
+}
+
+#define make_atomic_cas(S) \
+static inline uint _my_atomic_cas ## S(my_atomic_ ## S ## _t *a,\
+ uint ## S *cmp, uint ## S set) \
+{ \
+ uint8 ret; \
+ make_atomic_cas_body ## S; \
+ return ret; \
+}
+
+#define make_atomic_load(S) \
+static inline uint ## S _my_atomic_load ## S( \
+ my_atomic_ ## S ## _t *a) \
+{ \
+ uint ## S ret; \
+ make_atomic_load_body ## S; \
+ return ret; \
+}
+
+#define make_atomic_store(S) \
+static inline void _my_atomic_store ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v) \
+{ \
+ make_atomic_store_body ## S; \
+}
+
+#else /* no inline functions */
+
+#define make_atomic_add(S) \
+extern uint ## S _my_atomic_add ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v);
+
+#define make_atomic_swap(S) \
+extern uint ## S _my_atomic_swap ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v);
+
+#define make_atomic_cas(S) \
+extern uint _my_atomic_cas ## S(my_atomic_ ## S ## _t *a, \
+ uint ## S *cmp, uint ## S set);
+
+#define make_atomic_load(S) \
+extern uint ## S _my_atomic_load ## S( \
+ my_atomic_ ## S ## _t *a);
+
+#define make_atomic_store(S) \
+extern void _my_atomic_store ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v);
+
+#endif
+
+make_atomic_add( 8)
+make_atomic_add(16)
+make_atomic_add(32)
+
+make_atomic_cas( 8)
+make_atomic_cas(16)
+make_atomic_cas(32)
+
+make_atomic_load( 8)
+make_atomic_load(16)
+make_atomic_load(32)
+
+make_atomic_store( 8)
+make_atomic_store(16)
+make_atomic_store(32)
+
+make_atomic_swap( 8)
+make_atomic_swap(16)
+make_atomic_swap(32)
+
+#undef make_atomic_add_body8
+#undef make_atomic_cas_body8
+#undef make_atomic_load_body8
+#undef make_atomic_store_body8
+#undef make_atomic_swap_body8
+#undef make_atomic_add_body16
+#undef make_atomic_cas_body16
+#undef make_atomic_load_body16
+#undef make_atomic_store_body16
+#undef make_atomic_swap_body16
+#undef make_atomic_add_body32
+#undef make_atomic_cas_body32
+#undef make_atomic_load_body32
+#undef make_atomic_store_body32
+#undef make_atomic_swap_body32
+#undef make_atomic_add
+#undef make_atomic_cas
+#undef make_atomic_load
+#undef make_atomic_store
+#undef make_atomic_swap
+
+#define my_atomic_add8(a,v,L) _my_atomic_add8(a,v)
+#define my_atomic_add16(a,v,L) _my_atomic_add16(a,v)
+#define my_atomic_add32(a,v,L) _my_atomic_add32(a,v)
+
+#define my_atomic_cas8(a,c,v,L) _my_atomic_cas8(a,c,v)
+#define my_atomic_cas16(a,c,v,L) _my_atomic_cas16(a,c,v)
+#define my_atomic_cas32(a,c,v,L) _my_atomic_cas32(a,c,v)
+
+#define my_atomic_load8(a,L) _my_atomic_load8(a)
+#define my_atomic_load16(a,L) _my_atomic_load16(a)
+#define my_atomic_load32(a,L) _my_atomic_load32(a)
+
+#define my_atomic_store8(a,v,L) _my_atomic_store8(a,v)
+#define my_atomic_store16(a,v,L) _my_atomic_store16(a,v)
+#define my_atomic_store32(a,v,L) _my_atomic_store32(a,v)
+
+#define my_atomic_swap8(a,v,L) _my_atomic_swap8(a,v)
+#define my_atomic_swap16(a,v,L) _my_atomic_swap16(a,v)
+#define my_atomic_swap32(a,v,L) _my_atomic_swap32(a,v)
+
+#define my_atomic_rwlock_t typedef int
+#define my_atomic_rwlock_destroy(name)
+#define my_atomic_rwlock_init(name)
+#define my_atomic_rwlock_rdlock(name)
+#define my_atomic_rwlock_wrlock(name)
+#define my_atomic_rwlock_rdunlock(name)
+#define my_atomic_rwlock_wrunlock(name)
+
+#endif
+
diff --git a/include/atomic/rwlock.h b/include/atomic/rwlock.h
new file mode 100644
index 00000000000..ca5be29ab9b
--- /dev/null
+++ b/include/atomic/rwlock.h
@@ -0,0 +1,161 @@
+/* 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 */
+
+typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
+
+#ifdef MY_ATOMIC_EXTRA_DEBUG
+#define CHECK_RW if (rw) if (a->rw) assert(rw == a->rw); else a->rw=rw;
+#else
+#define CHECK_RW
+#endif
+
+#ifdef MY_ATOMIC_MODE_DUMMY
+/*
+ the following can never be enabled by ./configure, one need to put #define in
+ a source to trigger the following warning. The resulting code will be broken,
+ it only makes sense to do it to see now test_atomic detects broken
+ implementations (another way is to run a UP build on an SMP box).
+*/
+#warning MY_ATOMIC_MODE_DUMMY and MY_ATOMIC_MODE_RWLOCKS are incompatible
+#define my_atomic_rwlock_destroy(name)
+#define my_atomic_rwlock_init(name)
+#define my_atomic_rwlock_rdlock(name)
+#define my_atomic_rwlock_wrlock(name)
+#define my_atomic_rwlock_rdunlock(name)
+#define my_atomic_rwlock_wrunlock(name)
+#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)
+#endif
+
+#ifdef HAVE_INLINE
+
+#define make_atomic_add(S) \
+static inline uint ## S my_atomic_add ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw) \
+{ \
+ uint ## S ret; \
+ CHECK_RW; \
+ if (rw) my_atomic_rwlock_wrlock(rw); \
+ ret= a->val; \
+ a->val+= v; \
+ if (rw) my_atomic_rwlock_wrunlock(rw); \
+ return ret; \
+}
+
+#define make_atomic_swap(S) \
+static inline uint ## S my_atomic_swap ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw) \
+{ \
+ uint ## S ret; \
+ CHECK_RW; \
+ if (rw) my_atomic_rwlock_wrlock(rw); \
+ ret= a->val; \
+ a->val= v; \
+ if (rw) my_atomic_rwlock_wrunlock(rw); \
+ return ret; \
+}
+
+#define make_atomic_cas(S) \
+static inline uint my_atomic_cas ## S(my_atomic_ ## S ## _t *a, \
+ uint ## S *cmp, uint ## S set, my_atomic_rwlock_t *rw) \
+{ \
+ uint ret; \
+ CHECK_RW; \
+ if (rw) my_atomic_rwlock_wrlock(rw); \
+ if (ret= (a->val == *cmp)) a->val= set; else *cmp=a->val; \
+ if (rw) my_atomic_rwlock_wrunlock(rw); \
+ return ret; \
+}
+
+#define make_atomic_load(S) \
+static inline uint ## S my_atomic_load ## S( \
+ my_atomic_ ## S ## _t *a, my_atomic_rwlock_t *rw) \
+{ \
+ uint ## S ret; \
+ CHECK_RW; \
+ if (rw) my_atomic_rwlock_wrlock(rw); \
+ ret= a->val; \
+ if (rw) my_atomic_rwlock_wrunlock(rw); \
+ return ret; \
+}
+
+#define make_atomic_store(S) \
+static inline void my_atomic_store ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw) \
+{ \
+ CHECK_RW; \
+ if (rw) my_atomic_rwlock_rdlock(rw); \
+ (a)->val= (v); \
+ if (rw) my_atomic_rwlock_rdunlock(rw); \
+}
+
+#else /* no inline functions */
+
+#define make_atomic_add(S) \
+extern uint ## S my_atomic_add ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw);
+
+#define make_atomic_swap(S) \
+extern uint ## S my_atomic_swap ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw);
+
+#define make_atomic_cas(S) \
+extern uint my_atomic_cas ## S(my_atomic_ ## S ## _t *a, \
+ uint ## S *cmp, uint ## S set, my_atomic_rwlock_t *rw);
+
+#define make_atomic_load(S) \
+extern uint ## S my_atomic_load ## S( \
+ my_atomic_ ## S ## _t *a, my_atomic_rwlock_t *rw);
+
+#define make_atomic_store(S) \
+extern void my_atomic_store ## S( \
+ my_atomic_ ## S ## _t *a, uint ## S v, my_atomic_rwlock_t *rw);
+
+#endif
+
+make_atomic_add( 8)
+make_atomic_add(16)
+make_atomic_add(32)
+make_atomic_add(64)
+make_atomic_cas( 8)
+make_atomic_cas(16)
+make_atomic_cas(32)
+make_atomic_cas(64)
+make_atomic_load( 8)
+make_atomic_load(16)
+make_atomic_load(32)
+make_atomic_load(64)
+make_atomic_store( 8)
+make_atomic_store(16)
+make_atomic_store(32)
+make_atomic_store(64)
+make_atomic_swap( 8)
+make_atomic_swap(16)
+make_atomic_swap(32)
+make_atomic_swap(64)
+#undef make_atomic_add
+#undef make_atomic_cas
+#undef make_atomic_load
+#undef make_atomic_store
+#undef make_atomic_swap
+#undef CHECK_RW
+
+
diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h
new file mode 100644
index 00000000000..7576db54d69
--- /dev/null
+++ b/include/atomic/x86-gcc.h
@@ -0,0 +1,59 @@
+/* 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 */
+
+/*
+ XXX 64-bit atomic operations can be implemented using
+ cmpxchg8b, if necessary
+*/
+
+/* fix -ansi errors while maintaining readability */
+#define asm __asm__
+
+#define make_atomic_add_body8 \
+ asm volatile (LOCK "xadd %0, %1;" : "+r" (v) , "+m" (a->val))
+#define make_atomic_swap_body8 \
+ asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (a->val))
+#define make_atomic_cas_body8 \
+ asm volatile (LOCK "cmpxchg %3, %0; setz %2;" \
+ : "+m" (a->val), "+a" (*cmp), "=q" (ret): "r" (set))
+
+#ifdef MY_ATOMIC_MODE_DUMMY
+#define make_atomic_load_body8 ret=a->val
+#define make_atomic_store_body8 a->val=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_body8 \
+ ret=0; \
+ asm volatile (LOCK "cmpxchg %2, %0" \
+ : "+m" (a->val), "+a" (ret): "r" (ret))
+#define make_atomic_store_body8 \
+ asm volatile ("xchg %0, %1;" : "+m" (a->val) : "r" (v))
+#endif
+
+#define make_atomic_add_body16 make_atomic_add_body8
+#define make_atomic_add_body32 make_atomic_add_body8
+#define make_atomic_cas_body16 make_atomic_cas_body8
+#define make_atomic_cas_body32 make_atomic_cas_body8
+#define make_atomic_load_body16 make_atomic_load_body8
+#define make_atomic_load_body32 make_atomic_load_body8
+#define make_atomic_store_body16 make_atomic_store_body8
+#define make_atomic_store_body32 make_atomic_store_body8
+#define make_atomic_swap_body16 make_atomic_swap_body8
+#define make_atomic_swap_body32 make_atomic_swap_body8
+
diff --git a/include/atomic/x86-msvc.h b/include/atomic/x86-msvc.h
new file mode 100644
index 00000000000..19645551196
--- /dev/null
+++ b/include/atomic/x86-msvc.h
@@ -0,0 +1,85 @@
+/* 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 */
+
+/*
+ XXX 64-bit atomic operations can be implemented using
+ cmpxchg8b, if necessary
+*/
+
+// Would it be better to use intrinsics ?
+// (InterlockedCompareExchange, InterlockedCompareExchange16
+// InterlockedExchangeAdd, InterlockedExchange)
+
+#define make_atomic_add_body(REG) \
+ _asm { \
+ _asm mov REG, v \
+ _asm LOCK xadd a->val, REG \
+ _asm movzx v, REG \
+ }
+#define make_atomic_cas_body(AREG,REG2) \
+ _asm { \
+ _asm mov AREG, *cmp \
+ _asm mov REG2, set \
+ _asm LOCK cmpxchg a->val, REG2 \
+ _asm mov *cmp, AREG \
+ _asm setz al \
+ _asm movzx ret, al \
+ }
+#define make_atomic_swap_body(REG) \
+ _asm { \
+ _asm mov REG, v \
+ _asm xchg a->val, REG \
+ _asm mov v, REG \
+ }
+
+#ifdef MY_ATOMIC_MODE_DUMMY
+#define make_atomic_load_body(AREG,REG) ret=a->val
+#define make_atomic_store_body(REG) a->val=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(AREG,REG2) \
+ _asm { \
+ _asm mov AREG, 0 \
+ _asm mov REG2, AREG \
+ _asm LOCK cmpxchg a->val, REG2 \
+ _asm mov ret, AREG \
+ }
+#define make_atomic_store_body(REG) \
+ _asm { \
+ _asm mov REG, v \
+ _asm xchg a->val, REG \
+ }
+#endif
+
+#define make_atomic_add_body8 make_atomic_add_body(al)
+#define make_atomic_add_body16 make_atomic_add_body(ax)
+#define make_atomic_add_body32 make_atomic_add_body(eax)
+#define make_atomic_cas_body8 make_atomic_cas_body(al, bl)
+#define make_atomic_cas_body16 make_atomic_cas_body(ax, bx)
+#define make_atomic_cas_body32 make_atomic_cas_body(eax, ebx)
+#define make_atomic_load_body8 make_atomic_load_body(al, bl)
+#define make_atomic_load_body16 make_atomic_load_body(ax, bx)
+#define make_atomic_load_body32 make_atomic_load_body(eax, ebx)
+#define make_atomic_store_body8 make_atomic_store_body(al)
+#define make_atomic_store_body16 make_atomic_store_body(ax)
+#define make_atomic_store_body32 make_atomic_store_body(eax)
+#define make_atomic_swap_body8 make_atomic_swap_body(al)
+#define make_atomic_swap_body16 make_atomic_swap_body(ax)
+#define make_atomic_swap_body32 make_atomic_swap_body(eax)
+
diff --git a/include/base64.h b/include/base64.h
index a2b0fc0352b..4653e824a9a 100644
--- a/include/base64.h
+++ b/include/base64.h
@@ -21,8 +21,6 @@
extern "C" {
#endif
-#include <my_global.h>
-
/*
Calculate how much memory needed for dst of base64_encode()
*/
diff --git a/include/config-win.h b/include/config-win.h
index c0b1101fe76..c994a0ee7e9 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -25,6 +25,7 @@ functions */
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Avoid endless warnings about sprintf() etc. being unsafe. */
#define _CRT_SECURE_NO_DEPRECATE 1
+#define _USE_32BIT_TIME_T 1 /* force time_t to be 32 bit */
#endif
#include <sys/locking.h>
@@ -94,7 +95,7 @@ functions */
#define O_SHORT_LIVED 0
#define SH_DENYNO _SH_DENYNO
#else
-#define O_BINARY _O_BINARY /* compability with MSDOS */
+#define O_BINARY _O_BINARY /* compability with older style names */
#define FILE_BINARY _O_BINARY /* my_fopen in binary mode */
#define O_TEMPORARY _O_TEMPORARY
#define O_SHORT_LIVED _O_SHORT_LIVED
diff --git a/include/heap.h b/include/heap.h
index 855cff117e2..985b20f9dc9 100644
--- a/include/heap.h
+++ b/include/heap.h
@@ -111,7 +111,7 @@ struct st_heap_info; /* For referense */
typedef struct st_hp_keydef /* Key definition with open */
{
- uint flag; /* HA_NOSAME | HA_NULL_PART_KEY */
+ uint flag; /* HA_NOSAME | HA_NULL_PART_KEY */
uint keysegs; /* Number of key-segment */
uint length; /* Length of key (automatic) */
uint8 algorithm; /* HASH / BTREE */
@@ -209,6 +209,7 @@ extern int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
extern int heap_delete_table(const char *name);
extern void heap_drop_table(HP_INFO *info);
extern int heap_extra(HP_INFO *info,enum ha_extra_function function);
+extern int heap_reset(HP_INFO *info);
extern int heap_rename(const char *old_name,const char *new_name);
extern int heap_panic(enum ha_panic_function flag);
extern int heap_rsame(HP_INFO *info,byte *record,int inx);
diff --git a/include/m_string.h b/include/m_string.h
index e73f5c11487..9f7ec220f2c 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -106,12 +106,6 @@ extern char NEAR _dig_vec_lower[];
#define memcpy_fixed(A,B,C) memcpy((A),(B),(C))
#endif
-#ifdef MSDOS
-#undef bmove_align
-#define bmove512(A,B,C) bmove_align(A,B,C)
-extern void bmove_align(gptr dst,const gptr src,uint len);
-#endif
-
#if (!defined(USE_BMOVE512) || defined(HAVE_purify)) && !defined(bmove512)
#define bmove512(A,B,C) memcpy(A,B,C)
#endif
@@ -246,4 +240,22 @@ extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
#if defined(__cplusplus)
}
#endif
+
+/*
+ LEX_STRING -- a pair of a C-string and its length.
+
+ NOTE: this exactly form of declaration is required for some C-compilers
+ (for one, Sun C 5.7 2005/01/07). Unfortunatelt with such declaration
+ LEX_STRING can not be forward declared.
+*/
+
+typedef struct
+{
+ char *str;
+ uint length;
+} LEX_STRING;
+
+#define STRING_WITH_LEN(X) (X), ((uint) (sizeof(X) - 1))
+#define C_STRING_WITH_SIZE(X) ((char *) (X)), ((uint) (sizeof(X) - 1))
+
#endif
diff --git a/include/my_atomic.h b/include/my_atomic.h
new file mode 100644
index 00000000000..091edc0f57b
--- /dev/null
+++ b/include/my_atomic.h
@@ -0,0 +1,46 @@
+/* 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 */
+
+#ifndef atomic_rwlock_init
+
+#ifdef MY_ATOMIC_EXTRA_DEBUG
+#ifndef MY_ATOMIC_MODE_RWLOCKS
+#error MY_ATOMIC_EXTRA_DEBUG can be only used with MY_ATOMIC_MODE_RWLOCKS
+#endif
+#define LOCK_PTR void *rw;
+#else
+#define LOCK_PTR
+#endif
+
+typedef volatile struct {uint8 val; LOCK_PTR} my_atomic_8_t;
+typedef volatile struct {uint16 val; LOCK_PTR} my_atomic_16_t;
+typedef volatile struct {uint32 val; LOCK_PTR} my_atomic_32_t;
+typedef volatile struct {uint64 val; LOCK_PTR} my_atomic_64_t;
+
+#ifndef MY_ATOMIC_MODE_RWLOCKS
+#include "atomic/nolock.h"
+#endif
+
+#ifndef my_atomic_rwlock_init
+#include "atomic/rwlock.h"
+#endif
+
+#define MY_ATOMIC_OK 0
+#define MY_ATOMIC_NOT_1CPU 1
+extern int my_atomic_initialize();
+
+#endif
+
diff --git a/include/my_base.h b/include/my_base.h
index 74dc9855a3b..4bcfb03affb 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -32,9 +32,6 @@
#define EOVERFLOW 84
#endif
-#ifdef MSDOS
-#include <share.h> /* Neaded for sopen() */
-#endif
#if !defined(USE_MY_FUNC) && !defined(THREAD)
#include <my_nosys.h> /* For faster code, after test */
#endif /* USE_MY_FUNC */
@@ -104,7 +101,7 @@ enum ha_key_alg {
enum ha_extra_function {
HA_EXTRA_NORMAL=0, /* Optimize for space (def) */
HA_EXTRA_QUICK=1, /* Optimize for speed */
- HA_EXTRA_RESET=2, /* Reset database to after open */
+ HA_EXTRA_NOT_USED=2,
HA_EXTRA_CACHE=3, /* Cache record in HA_rrnd() */
HA_EXTRA_NO_CACHE=4, /* End caching of records (def) */
HA_EXTRA_NO_READCHECK=5, /* No readcheck on update */
@@ -130,15 +127,6 @@ enum ha_extra_function {
HA_EXTRA_RESET_STATE, /* Reset positions */
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
HA_EXTRA_NO_IGNORE_DUP_KEY,
- /*
- Instructs InnoDB to retrieve all columns (except in key read), not just
- those where field->query_id is the same as the current query id
- */
- HA_EXTRA_RETRIEVE_ALL_COLS,
- /*
- Instructs InnoDB to retrieve at least all the primary key columns
- */
- HA_EXTRA_RETRIEVE_PRIMARY_KEY,
HA_EXTRA_PREPARE_FOR_DELETE,
HA_EXTRA_PREPARE_FOR_UPDATE, /* Remove read cache if problems */
HA_EXTRA_PRELOAD_BUFFER_SIZE, /* Set buffer size for preloading */
diff --git a/include/my_bitmap.h b/include/my_bitmap.h
index 428ca7dc702..0b16a1b4832 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -17,19 +17,18 @@
#ifndef _my_bitmap_h_
#define _my_bitmap_h_
-#ifdef THREAD
-#include <my_pthread.h>
-#endif
-
#define MY_BIT_NONE (~(uint) 0)
+#include <m_string.h>
+
+typedef uint32 my_bitmap_map;
typedef struct st_bitmap
{
- uint32 *bitmap;
+ my_bitmap_map *bitmap;
uint n_bits; /* number of bits occupied by the above */
- uint32 last_word_mask;
- uint32 *last_word_ptr;
+ my_bitmap_map last_word_mask;
+ my_bitmap_map *last_word_ptr;
/*
mutex will be acquired for the duration of each bitmap operation if
thread_safe flag in bitmap_init was set. Otherwise, we optimize by not
@@ -43,12 +42,16 @@ typedef struct st_bitmap
#ifdef __cplusplus
extern "C" {
#endif
-extern my_bool bitmap_init(MY_BITMAP *map, uint32 *buf, uint n_bits, my_bool thread_safe);
+extern my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
+ my_bool thread_safe);
extern my_bool bitmap_is_clear_all(const MY_BITMAP *map);
extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size);
extern my_bool bitmap_is_set_all(const MY_BITMAP *map);
extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2);
+extern my_bool bitmap_is_overlapping(const MY_BITMAP *map1,
+ const MY_BITMAP *map2);
extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit);
+extern my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit);
extern uint bitmap_set_next(MY_BITMAP *map);
extern uint bitmap_get_first(const MY_BITMAP *map);
@@ -62,6 +65,7 @@ extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_invert(MY_BITMAP *map);
+extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2);
extern uint bitmap_lock_set_next(MY_BITMAP *map);
extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit);
@@ -88,7 +92,7 @@ extern void bitmap_lock_xor(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_lock_invert(MY_BITMAP *map);
#endif
/* Fast, not thread safe, bitmap functions */
-#define bitmap_buffer_size(bits) 4*(((bits)+31)/32);
+#define bitmap_buffer_size(bits) (((bits)+31)/32)*4
#define no_bytes_in_map(map) (((map)->n_bits + 7)/8)
#define no_words_in_map(map) (((map)->n_bits + 31)/32)
#define bytes_word_aligned(bytes) (4*((bytes + 3)/4))
@@ -98,28 +102,28 @@ extern void bitmap_lock_invert(MY_BITMAP *map);
^= (1 << ((BIT) & 7)))
#define _bitmap_clear_bit(MAP, BIT) (((uchar*)(MAP)->bitmap)[(BIT) / 8] \
&= ~ (1 << ((BIT) & 7)))
-#define _bitmap_is_set(MAP, BIT) (((uchar*)(MAP)->bitmap)[(BIT) / 8] \
- & (1 << ((BIT) & 7)))
+#define _bitmap_is_set(MAP, BIT) (uint) (((uchar*)(MAP)->bitmap)[(BIT) / 8] \
+ & (1 << ((BIT) & 7)))
#ifndef DBUG_OFF
-static inline uint32
+static inline void
bitmap_set_bit(MY_BITMAP *map,uint bit)
{
DBUG_ASSERT(bit < (map)->n_bits);
- return _bitmap_set_bit(map,bit);
+ _bitmap_set_bit(map,bit);
}
-static inline uint32
+static inline void
bitmap_flip_bit(MY_BITMAP *map,uint bit)
{
DBUG_ASSERT(bit < (map)->n_bits);
- return _bitmap_flip_bit(map,bit);
+ _bitmap_flip_bit(map,bit);
}
-static inline uint32
+static inline void
bitmap_clear_bit(MY_BITMAP *map,uint bit)
{
DBUG_ASSERT(bit < (map)->n_bits);
- return _bitmap_clear_bit(map,bit);
+ _bitmap_clear_bit(map,bit);
}
-static inline uint32
+static inline uint
bitmap_is_set(const MY_BITMAP *map,uint bit)
{
DBUG_ASSERT(bit < (map)->n_bits);
@@ -131,11 +135,16 @@ bitmap_is_set(const MY_BITMAP *map,uint bit)
#define bitmap_clear_bit(MAP, BIT) _bitmap_clear_bit(MAP, BIT)
#define bitmap_is_set(MAP, BIT) _bitmap_is_set(MAP, BIT)
#endif
-#define bitmap_cmp(MAP1, MAP2) \
- (memcmp((MAP1)->bitmap, (MAP2)->bitmap, 4*no_words_in_map((MAP1)))==0)
+
+static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
+{
+ *(map1)->last_word_ptr|= (map1)->last_word_mask;
+ *(map2)->last_word_ptr|= (map2)->last_word_mask;
+ return memcmp((map1)->bitmap, (map2)->bitmap, 4*no_words_in_map((map1)))==0;
+}
+
#define bitmap_clear_all(MAP) \
- { memset((MAP)->bitmap, 0, 4*no_words_in_map((MAP))); \
- *(MAP)->last_word_ptr|= (MAP)->last_word_mask; }
+ { memset((MAP)->bitmap, 0, 4*no_words_in_map((MAP))); }
#define bitmap_set_all(MAP) \
(memset((MAP)->bitmap, 0xFF, 4*no_words_in_map((MAP))))
diff --git a/include/my_global.h b/include/my_global.h
index 100e695a0de..f2ad3af0b6f 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -181,6 +181,17 @@
#define HOT_DATA
#endif
+/*
+ now let's figure out if inline functions are supported
+ autoconf defines 'inline' to be empty, if not
+*/
+#define inline_test_1(X) X ## 1
+#define inline_test_2(X) inline_test_1(X)
+#if inline_test_2(inline) != 1
+#define HAVE_INLINE
+#endif
+#undef inline_test_2
+#undef inline_test_1
/*
The following macros are used to control inlining a bit more than
@@ -853,26 +864,36 @@ typedef void *gptr; /* Generic pointer */
#else
typedef char *gptr; /* Generic pointer */
#endif
-#ifndef HAVE_INT_8_16_32
-typedef signed char int8; /* Signed integer >= 8 bits */
-typedef short int16; /* Signed integer >= 16 bits */
-#endif
#ifndef HAVE_UCHAR
typedef unsigned char uchar; /* Short for unsigned char */
#endif
-typedef unsigned char uint8; /* Short for unsigned integer >= 8 bits */
-typedef unsigned short uint16; /* Short for unsigned integer >= 16 bits */
+#ifndef HAVE_INT8
+typedef signed char int8; /* Signed integer >= 8 bits */
+#endif
+#ifndef HAVE_UINT8
+typedef unsigned char uint8; /* Unsigned integer >= 8 bits */
+#endif
+#ifndef HAVE_INT16
+typedef short int16;
+#endif
+#ifndef HAVE_UINT16
+typedef unsigned short uint16;
+#endif
#if SIZEOF_INT == 4
-#ifndef HAVE_INT_8_16_32
-typedef int int32;
+#ifndef HAVE_INT32
+typedef int int32;
+#endif
+#ifndef HAVE_UINT32
+typedef unsigned int uint32;
#endif
-typedef unsigned int uint32; /* Short for unsigned integer >= 32 bits */
#elif SIZEOF_LONG == 4
-#ifndef HAVE_INT_8_16_32
-typedef long int32;
+#ifndef HAVE_INT32
+typedef long int32;
+#endif
+#ifndef HAVE_UINT32
+typedef unsigned long uint32;
#endif
-typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */
#else
#error "Neither int or long is of 4 bytes width"
#endif
@@ -889,6 +910,12 @@ typedef unsigned long ulonglong; /* ulong or unsigned long long */
typedef long longlong;
#endif
#endif
+#ifndef HAVE_INT64
+typedef longlong int64;
+#endif
+#ifndef HAVE_UINT64
+typedef ulonglong uint64;
+#endif
#if defined(NO_CLIENT_LONG_LONG)
typedef unsigned long my_ulonglong;
diff --git a/include/my_net.h b/include/my_net.h
index f953a832e6b..b26e525016b 100644
--- a/include/my_net.h
+++ b/include/my_net.h
@@ -44,7 +44,7 @@ C_MODE_START
#include <sys/ioctl.h>
#endif
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__NETWARE__)
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
@@ -53,7 +53,7 @@ C_MODE_START
#endif
#endif
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#define O_NONBLOCK 1 /* For emulation of fcntl() */
#endif
diff --git a/include/my_nosys.h b/include/my_nosys.h
index 605906f0e07..41b919c1a72 100644
--- a/include/my_nosys.h
+++ b/include/my_nosys.h
@@ -27,9 +27,6 @@ extern "C" {
#ifndef __MY_NOSYS__
#define __MY_NOSYS__
-#ifdef MSDOS
-#include <io.h> /* Get prototypes for read()... */
-#endif
#ifndef HAVE_STDLIB_H
#include <malloc.h>
#endif
diff --git a/include/my_pthread.h b/include/my_pthread.h
index acd1d2b558b..0cb38d29be8 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -226,12 +226,14 @@ int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */
we want to make sure that no such flags are set.
*/
#if defined(HAVE_SIGACTION) && !defined(my_sigset)
-#define my_sigset(A,B) do { struct sigaction s; sigset_t set; \
+#define my_sigset(A,B) do { struct sigaction s; sigset_t set; int rc; \
+ DBUG_ASSERT((A) != 0); \
sigemptyset(&set); \
s.sa_handler = (B); \
s.sa_mask = set; \
s.sa_flags = 0; \
- sigaction((A), &s, (struct sigaction *) NULL); \
+ rc= sigaction((A), &s, (struct sigaction *) NULL);\
+ DBUG_ASSERT(rc == 0); \
} while (0)
#elif defined(HAVE_SIGSET) && !defined(my_sigset)
#define my_sigset(A,B) sigset((A),(B))
diff --git a/include/my_sys.h b/include/my_sys.h
index 0a4881e2082..4ea7cecf0a1 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -77,6 +77,10 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_GIVE_INFO 2 /* Give time info about process*/
#define MY_DONT_FREE_DBUG 4 /* Do not call DBUG_END() in my_end() */
+#define MY_REMOVE_NONE 0 /* Params for modify_defaults_file */
+#define MY_REMOVE_OPTION 1
+#define MY_REMOVE_SECTION 2
+
#define ME_HIGHBYTE 8 /* Shift for colours */
#define ME_NOCUR 1 /* Don't use curses message */
#define ME_OLDWIN 2 /* Use old window */
@@ -197,22 +201,6 @@ extern void my_large_free(gptr ptr, myf my_flags);
#define my_afree(PTR) my_free(PTR,MYF(MY_WME))
#endif /* HAVE_ALLOCA */
-#ifdef MSDOS
-#ifdef __ZTC__
-void * __CDECL halloc(long count,size_t length);
-void __CDECL hfree(void *ptr);
-#endif
-#if defined(USE_HALLOC)
-#if defined(_VCM_) || defined(M_IC80386)
-#undef USE_HALLOC
-#endif
-#endif
-#ifdef USE_HALLOC
-#define malloc(a) halloc((long) (a),1)
-#define free(a) hfree(a)
-#endif
-#endif /* MSDOS */
-
#ifndef errno /* did we already get it? */
#ifdef HAVE_ERRNO_AS_DEFINE
#include <errno.h> /* errno is a define */
@@ -833,8 +821,9 @@ extern ulong crc32(ulong crc, const uchar *buf, uint len);
extern uint my_set_max_open_files(uint files);
void my_free_open_file_info(void);
-ulonglong my_getsystime(void);
-my_bool my_gethwaddr(uchar *to);
+extern ulonglong my_getsystime(void);
+extern my_bool my_gethwaddr(uchar *to);
+extern int my_getncpus();
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
diff --git a/include/my_tree.h b/include/my_tree.h
index 03dc9d5c829..e9746ca1b2c 100644
--- a/include/my_tree.h
+++ b/include/my_tree.h
@@ -40,19 +40,11 @@ typedef int (*tree_walk_action)(void *,element_count,void *);
typedef enum { free_init, free_free, free_end } TREE_FREE;
typedef void (*tree_element_free)(void*, TREE_FREE, void *);
-#ifdef MSDOS
-typedef struct st_tree_element {
- struct st_tree_element *left,*right;
- unsigned long count;
- uchar colour; /* black is marked as 1 */
-} TREE_ELEMENT;
-#else
typedef struct st_tree_element {
struct st_tree_element *left,*right;
uint32 count:31,
colour:1; /* black is marked as 1 */
} TREE_ELEMENT;
-#endif /* MSDOS */
#define ELEMENT_CHILD(element, offs) (*(TREE_ELEMENT**)((char*)element + offs))
diff --git a/include/myisam.h b/include/myisam.h
index db1a7bd984d..075779a6e42 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -303,6 +303,7 @@ extern int mi_rename(const char *from, const char *to);
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(struct st_myisam_info *info,int inx,
key_range *min_key, key_range *max_key);
extern int mi_log(int activate_log);
diff --git a/include/myisammrg.h b/include/myisammrg.h
index de8a36c2d0a..f23759e22e1 100644
--- a/include/myisammrg.h
+++ b/include/myisammrg.h
@@ -99,6 +99,7 @@ extern int myrg_create(const char *name, const char **table_names,
uint insert_method, my_bool fix_names);
extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function,
void *extra_arg);
+extern int myrg_reset(MYRG_INFO *info);
extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
key_range *min_key, key_range *max_key);
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index ab5ca6e7be4..0cee54bffde 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -28,7 +28,7 @@
*/
#define MYSQL_UDF_PLUGIN 0 /* User-defined function */
#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */
-#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text [pre]parser */
+#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */
#define MYSQL_MAX_PLUGIN_TYPE_NUM 3 /* The number of plugin types */
/*
@@ -95,12 +95,14 @@ struct st_mysql_plugin
};
/*************************************************************************
- API for Full-text [pre]parser plugin. (MYSQL_FTPARSER_PLUGIN)
+ API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN)
*/
-#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0000
+#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100
/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */
+enum enum_ftparser_mode
+{
/*
Fast and simple mode. This mode is used for indexing, and natural
language queries.
@@ -109,7 +111,7 @@ struct st_mysql_plugin
index. Stopwords or too short/long words should not be returned. The
'boolean_info' argument of mysql_add_word() does not have to be set.
*/
-#define MYSQL_FTPARSER_SIMPLE_MODE 0
+ MYSQL_FTPARSER_SIMPLE_MODE= 0,
/*
Parse with stopwords mode. This mode is used in boolean searches for
@@ -120,7 +122,7 @@ struct st_mysql_plugin
or long. The 'boolean_info' argument of mysql_add_word() does not
have to be set.
*/
-#define MYSQL_FTPARSER_WITH_STOPWORDS 1
+ MYSQL_FTPARSER_WITH_STOPWORDS= 1,
/*
Parse in boolean mode. This mode is used to parse a boolean query string.
@@ -133,7 +135,8 @@ struct st_mysql_plugin
MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored.
Instead, use FT_TOKEN_STOPWORD for the token type of such a word.
*/
-#define MYSQL_FTPARSER_FULL_BOOLEAN_INFO 2
+ MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2
+};
/*
Token types for boolean mode searching (used for the type member of
@@ -198,6 +201,17 @@ typedef struct st_mysql_ftparser_boolean_info
char *quot;
} MYSQL_FTPARSER_BOOLEAN_INFO;
+/*
+ The following flag means that buffer with a string (document, word)
+ may be overwritten by the caller before the end of the parsing (that is
+ before st_mysql_ftparser::deinit() call). If one needs the string
+ to survive between two successive calls of the parsing function, she
+ needs to save a copy of it. The flag may be set by MySQL before calling
+ st_mysql_ftparser::parse(), or it may be set by a plugin before calling
+ st_mysql_ftparser_param::mysql_parse() or
+ st_mysql_ftparser_param::mysql_add_word().
+*/
+#define MYSQL_FTFLAGS_NEED_COPY 1
/*
An argument of the full-text parser plugin. This structure is
@@ -209,22 +223,20 @@ typedef struct st_mysql_ftparser_boolean_info
to invoke the MySQL default parser. If plugin's role is to extract
textual data from .doc, .pdf or .xml content, it might extract
plaintext from the content, and then pass the text to the default
- MySQL parser to be parsed. When mysql_parser is called, its param
- argument should be given as the mysql_ftparam value.
+ MySQL parser to be parsed.
mysql_add_word: A server callback to add a new word. When parsing
a document, the server sets this to point at a function that adds
the word to MySQL full-text index. When parsing a search query,
this function will add the new word to the list of words to search
- for. When mysql_add_word is called, its param argument should be
- given as the mysql_ftparam value. boolean_info can be NULL for all
- cases except when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO.
+ for. The boolean_info argument can be NULL for all cases except
+ when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO.
ftparser_state: A generic pointer. The plugin can set it to point
to information to be used internally for its own purposes.
- mysql_ftparam: This is set by the server. It is passed as the first
- argument to the mysql_parse or mysql_add_word callback. The plugin
+ mysql_ftparam: This is set by the server. It is used by MySQL functions
+ called via mysql_parse() and mysql_add_word() callback. The plugin
should not modify it.
cs: Information about the character set of the document or query string.
@@ -233,21 +245,26 @@ typedef struct st_mysql_ftparser_boolean_info
length: Length of the document or query string, in bytes.
+ flags: See MYSQL_FTFLAGS_* constants above.
+
mode: The parsing mode. With boolean operators, with stopwords, or
- nothing. See MYSQL_FTPARSER_* constants above.
+ nothing. See enum_ftparser_mode above.
*/
typedef struct st_mysql_ftparser_param
{
- int (*mysql_parse)(void *param, char *doc, int doc_len);
- int (*mysql_add_word)(void *param, char *word, int word_len,
+ int (*mysql_parse)(struct st_mysql_ftparser_param *,
+ char *doc, int doc_len);
+ int (*mysql_add_word)(struct st_mysql_ftparser_param *,
+ char *word, int word_len,
MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
void *ftparser_state;
void *mysql_ftparam;
struct charset_info_st *cs;
char *doc;
int length;
- int mode;
+ int flags;
+ enum enum_ftparser_mode mode;
} MYSQL_FTPARSER_PARAM;
/*
@@ -265,5 +282,25 @@ struct st_mysql_ftparser
int (*init)(MYSQL_FTPARSER_PARAM *param);
int (*deinit)(MYSQL_FTPARSER_PARAM *param);
};
+
+/*************************************************************************
+ API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN)
+*/
+
+/* handlertons of different MySQL releases are incompatible */
+#define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
+
+/*
+ The real API is in the sql/handler.h
+ Here we define only the descriptor structure, that is referred from
+ st_mysql_plugin.
+*/
+
+struct st_mysql_storage_engine
+{
+ int interface_version;
+ struct handlerton *handlerton;
+};
+
#endif
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 2af0fb86906..623aaf43783 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -98,6 +98,7 @@ enum enum_server_command
#define BINCMP_FLAG 131072 /* Intern: Used by sql_yacc */
#define GET_FIXED_FIELDS_FLAG (1 << 18) /* Used to get fields in item tree */
#define FIELD_IN_PART_FUNC_FLAG (1 << 19)/* Field part of partition func */
+#define FIELD_IN_ADD_INDEX (1<< 20) /* Intern: Field used in ADD INDEX */
#define REFRESH_GRANT 1 /* Refresh grant tables */
#define REFRESH_LOG 2 /* Start on new log file */
@@ -423,17 +424,11 @@ char *octet2hex(char *to, const char *str, unsigned int len);
/* end of password.c */
-char *get_tty_password(char *opt_message);
+char *get_tty_password(const char *opt_message);
const char *mysql_errno_to_sqlstate(unsigned int mysql_errno);
/* Some other useful functions */
-my_bool my_init(void);
-extern int modify_defaults_file(const char *file_location, const char *option,
- const char *option_value,
- const char *section_name, int remove_option);
-int load_defaults(const char *conf_file, const char **groups,
- int *argc, char ***argv);
my_bool my_thread_init(void);
void my_thread_end(void);
diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h
index b0769af10fe..0435ddb815a 100644
--- a/include/sslopt-longopts.h
+++ b/include/sslopt-longopts.h
@@ -20,12 +20,6 @@
"Enable SSL for connection (automatically enabled with other flags). Disable with --skip-ssl.",
(gptr*) &opt_use_ssl, (gptr*) &opt_use_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
- {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).",
- (gptr*) &opt_ssl_key, (gptr*) &opt_ssl_key, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
- {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).",
- (gptr*) &opt_ssl_cert, (gptr*) &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
{"ssl-ca", OPT_SSL_CA,
"CA file in PEM format (check OpenSSL docs, implies --ssl).",
(gptr*) &opt_ssl_ca, (gptr*) &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG,
@@ -34,9 +28,15 @@
"CA directory (check OpenSSL docs, implies --ssl).",
(gptr*) &opt_ssl_capath, (gptr*) &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
+ {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).",
+ (gptr*) &opt_ssl_cert, (gptr*) &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
{"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).",
(gptr*) &opt_ssl_cipher, (gptr*) &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
+ {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).",
+ (gptr*) &opt_ssl_key, (gptr*) &opt_ssl_key, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
#ifdef MYSQL_CLIENT
{"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT,
"Verify server's \"Common Name\" in its cert against hostname used when connecting. This option is disabled by default.",
diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h
index 8e5f3434396..7204145fc28 100644
--- a/include/sslopt-vars.h
+++ b/include/sslopt-vars.h
@@ -15,13 +15,18 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef HAVE_OPENSSL
-static my_bool opt_use_ssl = 0;
-static char *opt_ssl_key = 0;
-static char *opt_ssl_cert = 0;
-static char *opt_ssl_ca = 0;
-static char *opt_ssl_capath = 0;
-static char *opt_ssl_cipher = 0;
+#ifdef SSL_VARS_NOT_STATIC
+#define SSL_STATIC
+#else
+#define SSL_STATIC static
+#endif
+SSL_STATIC my_bool opt_use_ssl = 0;
+SSL_STATIC char *opt_ssl_ca = 0;
+SSL_STATIC char *opt_ssl_capath = 0;
+SSL_STATIC char *opt_ssl_cert = 0;
+SSL_STATIC char *opt_ssl_cipher = 0;
+SSL_STATIC char *opt_ssl_key = 0;
#ifdef MYSQL_CLIENT
-static my_bool opt_ssl_verify_server_cert= 0;
+SSL_STATIC my_bool opt_ssl_verify_server_cert= 0;
#endif
#endif
diff --git a/include/violite.h b/include/violite.h
index 4837ade64b4..323e72e82d3 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -102,6 +102,7 @@ void vio_timeout(Vio *vio,uint which, uint timeout);
#define HEADER_DES_LOCL_H dummy_something
#define YASSL_MYSQL_COMPATIBLE
+#define YASSL_PREFIX
#include <openssl/ssl.h>
#include <openssl/err.h>
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 787ffc51de7..5e6c60a007b 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -24,7 +24,7 @@ target = libmysqlclient.la
target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
LIBS = @CLIENT_LIBS@
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
- $(openssl_includes) $(yassl_includes) @ZLIB_INCLUDES@
+ $(openssl_includes) @ZLIB_INCLUDES@
include $(srcdir)/Makefile.shared
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
index a48cb6d7a6e..4c251677a66 100644
--- a/libmysql/get_password.c
+++ b/libmysql/get_password.c
@@ -75,7 +75,7 @@
#define _cputs(A) putstring(A)
#endif
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
{
char to[80];
char *pos=to,*end=to+sizeof(to)-1;
@@ -159,7 +159,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
#endif /* ! HAVE_GETPASS */
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
{
#ifdef HAVE_GETPASS
char *passbuff;
diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am
index a1ccbca48e5..93f5bffdec7 100644
--- a/libmysql_r/Makefile.am
+++ b/libmysql_r/Makefile.am
@@ -25,7 +25,7 @@ target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@
LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
- $(openssl_includes) $(yassl_includes) @ZLIB_INCLUDES@
+ $(openssl_includes) @ZLIB_INCLUDES@
## automake barfs if you don't use $(srcdir) or $(top_srcdir) in include
include $(top_srcdir)/libmysql/Makefile.shared
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 8bd0e0baa32..ff8ceda5c5b 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -33,7 +33,7 @@ ADD_LIBRARY(mysqldemb emb_qcache.cc libmysqld.c lib_sql.cc
../sql/field_conv.cc ../sql/field.cc ../sql/filesort.cc
../sql/gstream.cc ../sql/ha_heap.cc ../sql/ha_myisam.cc
../sql/ha_myisammrg.cc ${mysql_se_ha_src}
- ../sql/handler.cc ../sql/handlerton-win.cc ../sql/hash_filo.cc
+ ../sql/handler.cc ../sql/hash_filo.cc
../sql/hostname.cc ../sql/init.cc ../sql/item_buff.cc
../sql/item_cmpfunc.cc ../sql/item.cc ../sql/item_create.cc
../sql/item_func.cc ../sql/item_geofunc.cc ../sql/item_row.cc
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index dab99d7509e..50f364babe1 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -32,7 +32,7 @@ INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_srcdir)/sql -I$(top_srcdir)/sql/examples \
-I$(top_srcdir)/regex \
- $(openssl_includes) $(yassl_includes) @ZLIB_INCLUDES@
+ $(openssl_includes) @ZLIB_INCLUDES@
noinst_LIBRARIES = libmysqld_int.a
pkglib_LIBRARIES = libmysqld.a
@@ -68,7 +68,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
- event_executor.cc event.cc event_timed.cc \
+ event_scheduler.cc event.cc event_timed.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc
@@ -88,11 +88,11 @@ INC_LIB= $(top_builddir)/regex/libregex.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/vio/libvio.a \
@mysql_plugin_libs@ \
- $(yassl_las)
+ $(yassl_inc_libs)
if HAVE_YASSL
-yassl_las = $(top_srcdir)/extra/yassl/src/libyassl.la \
- $(top_srcdir)/extra/yassl/taocrypt/src/libtaocrypt.la
+yassl_inc_libs= $(top_srcdir)/extra/yassl/src/.libs/libyassl.a \
+ $(top_srcdir)/extra/yassl/taocrypt/src/.libs/libtaocrypt.a
endif
# Storage engine specific compilation options
@@ -135,12 +135,12 @@ else
(for arc in ./libmysqld_int.a $(INC_LIB); do \
arpath=`echo $$arc|sed 's|[^/]*$$||'|sed 's|\.libs/$$||'`; \
artmp=`echo $$arc|sed 's|^.*/|tmp/lib-|'`; \
- for F in `$(AR) t $$arc`; do \
+ for F in `$(AR) t $$arc | grep -v SYMDEF`; do \
if test -e "$$arpath/$$F" ; then echo "$$arpath/$$F"; else \
mkdir $$artmp; cd $$artmp > /dev/null; \
$(AR) x ../../$$arc; \
cd $$current_dir > /dev/null; \
- ls $$artmp/*; \
+ ls $$artmp/* | grep -v SYMDEF; \
continue 2; fi; done; \
done; echo $(libmysqld_a_DEPENDENCIES) ) | sort -u | xargs $(AR) cq libmysqld.a ; \
$(RANLIB) libmysqld.a ; \
diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am
index 7ee8adfef80..c705fb1e68d 100644
--- a/libmysqld/examples/Makefile.am
+++ b/libmysqld/examples/Makefile.am
@@ -34,7 +34,7 @@ link_sources:
DEFS = -DEMBEDDED_LIBRARY
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \
-I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \
- $(openssl_includes) $(yassl_includes)
+ $(openssl_includes)
LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ $(yassl_libs)
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @LIBDL@ $(CXXLDFLAGS)
diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test
index ff43debf967..6f7990893f0 100644
--- a/mysql-test/extra/binlog_tests/binlog.test
+++ b/mysql-test/extra/binlog_tests/binlog.test
@@ -22,7 +22,7 @@ insert t2 values (5);
commit;
# first COMMIT must be Query_log_event, second - Xid_log_event
--replace_column 2 # 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
drop table t1,t2;
@@ -44,8 +44,8 @@ while ($1)
commit;
drop table t1;
--replace_column 2 # 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events in 'master-bin.000001' from 102;
--replace_column 2 # 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events in 'master-bin.000002' from 102;
diff --git a/mysql-test/extra/binlog_tests/innodb_stat.test b/mysql-test/extra/binlog_tests/innodb_stat.test
index 131c244d8fd..4638dfcd2f7 100644
--- a/mysql-test/extra/binlog_tests/innodb_stat.test
+++ b/mysql-test/extra/binlog_tests/innodb_stat.test
@@ -1,3 +1,5 @@
+# Embedded server doesn't support binlog
+-- source include/not_embedded.inc
-- source include/have_innodb.inc
#
diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
index b75a326d5a8..b5052620f91 100644
--- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
@@ -30,7 +30,7 @@ insert into t2 select * from t1;
commit;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -44,7 +44,7 @@ insert into t2 select * from t1;
rollback;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -60,7 +60,7 @@ rollback to savepoint my_savepoint;
commit;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -78,7 +78,7 @@ commit;
select a from t1 order by a; # check that savepoints work :)
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
# and when ROLLBACK is not explicit?
@@ -100,7 +100,7 @@ connection con2;
# logging has been done, we use a user lock.
select get_lock("a",10);
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
# and when not in a transact1on?
@@ -112,7 +112,7 @@ insert into t1 values(9);
insert into t2 select * from t1;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
# Check that when the query updat1ng the MyISAM table is the first in the
@@ -125,13 +125,13 @@ insert into t1 values(10); # first make t1 non-empty
begin;
insert into t2 select * from t1;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
insert into t1 values(11);
commit;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
@@ -150,7 +150,7 @@ insert into t2 select * from t1;
commit;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -163,7 +163,7 @@ insert into t2 select * from t1;
rollback;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -179,7 +179,7 @@ rollback to savepoint my_savepoint;
commit;
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
delete from t1;
@@ -197,7 +197,7 @@ commit;
select a from t1 order by a; # check that savepoints work :)
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
# Test for BUG#5714, where a MyISAM update in the transaction used to
@@ -234,8 +234,8 @@ select (@after-@before) >= 2;
drop table t1,t2;
commit;
-# test for BUG#7947 - DO RELEASE_LOCK() not written to binlog on rollback in the middle
-# of a transaction
+# test for BUG#7947 - DO RELEASE_LOCK() not written to binlog on rollback in
+# the middle of a transaction
connection con2;
begin;
@@ -258,13 +258,75 @@ disconnect con2;
connection con3;
select get_lock("lock1",60);
--replace_column 5 #
---replace_regex /table_id: [0-9]+/table_id: #/
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
show binlog events from 102;
do release_lock("lock1");
drop table t0,t2;
# End of 4.1 tests
+#
+# Test behaviour of CREATE ... SELECT when mixing MyISAM and InnoDB tables
+#
+
+set autocommit=0;
+CREATE TABLE t1 (a int, b int) engine=myisam;
+reset master;
+INSERT INTO t1 values (1,1),(1,2);
+--error 1062
+CREATE TABLE t2 (primary key (a)) engine=innodb select * from t1;
+# This should give warning
+DROP TABLE if exists t2;
+INSERT INTO t1 values (3,3);
+--error 1062
+CREATE TEMPORARY TABLE t2 (primary key (a)) engine=innodb select * from t1;
+ROLLBACK;
+# This should give warning
+DROP TABLE IF EXISTS t2;
+
+CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb;
+INSERT INTO t1 VALUES (4,4);
+--error 1062
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+SELECT * from t2;
+TRUNCATE table t2;
+INSERT INTO t1 VALUES (5,5);
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+INSERT INTO t1 values (6,6);
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)) engine=innodb ;
+INSERT INTO t1 values (7,7);
+ROLLBACK;
+INSERT INTO t1 values (8,8);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+COMMIT;
+INSERT INTO t1 values (9,9);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ROLLBACK;
+SELECT * from t2;
+TRUNCATE table t2;
+INSERT INTO t1 values (10,10);
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * from t1;
+INSERT INTO t2 values (100,100);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+COMMIT;
+INSERT INTO t2 values (101,101);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ROLLBACK;
+SELECT * from t2;
+DROP TABLE t1,t2;
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
+show binlog events from 102;
+
# Test for BUG#16559 (ROLLBACK should always have a zero error code in
# binlog). Has to be here and not earlier, as the SELECTs influence
# XIDs differently between normal and ps-protocol (and SHOW BINLOG
@@ -283,3 +345,4 @@ disconnect con3;
connection con4;
select get_lock("a",10); # wait for rollback to finish
+
diff --git a/mysql-test/extra/rpl_tests/rpl_insert_id.test b/mysql-test/extra/rpl_tests/rpl_insert_id.test
index 304fade7e1d..68e39c54381 100644
--- a/mysql-test/extra/rpl_tests/rpl_insert_id.test
+++ b/mysql-test/extra/rpl_tests/rpl_insert_id.test
@@ -156,3 +156,5 @@ drop function bug15728_insert;
drop table t1, t2;
# End of 5.0 tests
+
+sync_slave_with_master;
diff --git a/mysql-test/include/common-tests.inc b/mysql-test/include/common-tests.inc
index 46d0182d17f..882ac689498 100644
--- a/mysql-test/include/common-tests.inc
+++ b/mysql-test/include/common-tests.inc
@@ -1296,9 +1296,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
# The next should give an error
#
--- error 1072
+-- error 1176
explain select fld3 from t2 ignore index (fld3,not_used);
--- error 1072
+-- error 1176
explain select fld3 from t2 use index (not_used);
#
diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh
index 4554b92857e..9006957019a 100644
--- a/mysql-test/install_test_db.sh
+++ b/mysql-test/install_test_db.sh
@@ -34,7 +34,6 @@ if [ x$1 = x"-slave" ]
then
shift 1
data=var/slave-data
- ldata=$fix_bin/var/slave-data
else
if [ x$1 = x"-1" ]
then
@@ -42,8 +41,8 @@ else
else
data=var/master-data
fi
- ldata=$fix_bin/$data
fi
+ldata=$fix_bin/$data
mdata=$data/mysql
EXTRA_ARG=""
@@ -81,9 +80,7 @@ basedir=.
EXTRA_ARG="--language=../sql/share/english/ --character-sets-dir=../sql/share/charsets/"
fi
-mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \
- --basedir=$basedir --datadir=$ldata --skip-innodb --skip-ndbcluster --skip-bdb \
- $EXTRA_ARG"
+mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables --basedir=$basedir --datadir=$ldata --skip-innodb --skip-ndbcluster --skip-bdb --tmpdir=. $EXTRA_ARG"
echo "running $mysqld_boot"
if $scriptdir/mysql_create_system_tables test $mdata $hostname | $mysqld_boot
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql
index a7079b0ac33..a5736ed4b9b 100644
--- a/mysql-test/lib/init_db.sql
+++ b/mysql-test/lib/init_db.sql
@@ -631,7 +631,7 @@ CREATE TABLE event (
'HIGH_NOT_PRECEDENCE'
) DEFAULT '' NOT NULL,
comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- PRIMARY KEY (definer, db, name)
+ PRIMARY KEY (db, name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
CREATE DATABASE IF NOT EXISTS cluster;
diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl
index b5a2e5a4a68..bc44c440c32 100644
--- a/mysql-test/lib/mtr_misc.pl
+++ b/mysql-test/lib/mtr_misc.pl
@@ -108,7 +108,14 @@ sub mtr_exe_exists (@) {
map {$_.= ".exe"} @path if $::glob_win32;
foreach my $path ( @path )
{
- return $path if -x $path;
+ if($::glob_win32)
+ {
+ return $path if -f $path;
+ }
+ else
+ {
+ return $path if -x $path;
+ }
}
if ( @path == 1 )
{
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 872bc2de7bb..2d8dc588a36 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -691,6 +691,12 @@ sub command_line_setup () {
{
push(@opt_extra_mysqld_opt, $arg);
}
+ elsif ( $arg =~ /^--$/ )
+ {
+ # It is an effect of setting 'pass_through' in option processing
+ # that the lone '--' separating options from arguments survives,
+ # simply ignore it.
+ }
elsif ( $arg =~ /^-/ )
{
usage("Invalid option \"$arg\"");
@@ -1243,6 +1249,8 @@ sub executable_setup () {
sub environment_setup () {
+ umask(022);
+
# --------------------------------------------------------------------------
# We might not use a standard installation directory, like /usr/lib.
# Set LD_LIBRARY_PATH to make sure we find our installed libraries.
@@ -1291,9 +1299,12 @@ sub environment_setup () {
$ENV{'NDBCLUSTER_PORT_SLAVE'}=$opt_ndbcluster_port_slave;
$ENV{'NDB_STATUS_OK'}= "YES";
+ $ENV{'IM_EXE'}= $exe_im;
$ENV{'IM_PATH_PID'}= $instance_manager->{path_pid};
$ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid};
$ENV{'IM_PORT'}= $instance_manager->{port};
+ $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file};
+ $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file};
$ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock};
$ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port};
@@ -2009,6 +2020,7 @@ sub install_db ($$) {
mtr_add_arg($args, "--skip-innodb");
mtr_add_arg($args, "--skip-ndbcluster");
mtr_add_arg($args, "--skip-bdb");
+ mtr_add_arg($args, "--tmpdir=.");
if ( ! $opt_netware )
{
@@ -2504,7 +2516,6 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir);
mtr_add_arg($args, "%s--core", $prefix);
mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix);
- mtr_add_arg($args, "%s--loose-binlog-show-xid=0", $prefix);
mtr_add_arg($args, "%s--default-character-set=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
@@ -2654,7 +2665,6 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--sort_buffer=256K", $prefix);
mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix);
mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix);
- mtr_add_arg($args, "%s--loose-binlog-show-xid=0", $prefix);
if ( $opt_ssl_supported )
{
@@ -3499,7 +3509,7 @@ sub run_mysqltest ($) {
}
my $cmdline_mysql=
- "$exe_mysql --host=localhost --user=root --password= " .
+ "$exe_mysql --no-defaults --host=localhost --user=root --password= " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'}";
@@ -3942,6 +3952,13 @@ sub valgrind_arguments {
##############################################################################
sub usage ($) {
+ my $message= shift;
+
+ if ( $message )
+ {
+ print STDERR "$message \n";
+ }
+
print STDERR <<HERE;
mysql-test-run [ OPTIONS ] [ TESTCASE ]
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index f56099f3a49..4cbb1bece9c 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -1121,7 +1121,10 @@ mysql_install_db () {
if [ ! -z "$USE_NDBCLUSTER" ]
then
$ECHO "Installing Master Databases 1"
- $INSTALL_DB -1
+# $INSTALL_DB -1
+ $RM -rf var/master-data1
+ mkdir var/master-data1
+ cp -r var/master-data/* var/master-data1
if [ $? != 0 ]; then
error "Could not install master test DBs 1"
exit 1
@@ -1129,7 +1132,9 @@ mysql_install_db () {
fi
$ECHO "Installing Slave Databases"
$RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/*
- $INSTALL_DB -slave
+# $INSTALL_DB -slave
+ mkdir var/slave-data
+ cp -r var/master-data/* var/slave-data
if [ $? != 0 ]; then
error "Could not install slave test DBs"
exit 1
@@ -1345,7 +1350,6 @@ start_master()
--innodb_data_file_path=ibdata1:128M:autoextend \
--open-files-limit=1024 \
--log-bin-trust-function-creators \
- --loose-binlog-show-xid=0 \
$MASTER_40_ARGS \
$SMALL_SERVER \
$MASTER_MYSQLD_BINLOG_OPT \
@@ -1369,7 +1373,6 @@ start_master()
--language=$LANGUAGE \
--innodb_data_file_path=ibdata1:128M:autoextend \
--log-bin-trust-function-creators \
- --loose-binlog-show-xid=0 \
$MASTER_40_ARGS \
$SMALL_SERVER \
$MASTER_MYSQLD_BINLOG_OPT \
@@ -1542,7 +1545,6 @@ start_slave()
--master-retry-count=10 \
-O slave_net_timeout=10 \
--log-bin-trust-function-creators \
- --loose-binlog-show-xid=0 \
$SMALL_SERVER \
$SLAVE_MYSQLD_BINLOG_OPT \
$EXTRA_SLAVE_MYSQLD_OPT $EXTRA_SLAVE_OPT \
@@ -2158,6 +2160,7 @@ then
# Remove files that can cause problems
$RM -rf $MYSQL_TEST_DIR/var/ndbcluster
+ $RM -rf $MYSQL_TEST_DIR/var/tmp/snapshot*
$RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/*
# Remove old berkeley db log files that can confuse the server
diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result
index 09813458069..19cb0c9768f 100644
--- a/mysql-test/r/archive.result
+++ b/mysql-test/r/archive.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
CREATE TABLE t1 (
Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL
diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result
index 525f64ea902..d9e9392f618 100644
--- a/mysql-test/r/auto_increment.result
+++ b/mysql-test/r/auto_increment.result
@@ -418,3 +418,9 @@ a val
2 1
3 1
drop table t1;
+CREATE TABLE t1 (t1 INT(10) PRIMARY KEY, t2 INT(10));
+INSERT INTO t1 VALUES(0, 0);
+INSERT INTO t1 VALUES(1, 1);
+ALTER TABLE t1 CHANGE t1 t1 INT(10) auto_increment;
+ERROR 23000: ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '1' for key 'PRIMARY'
+DROP TABLE t1;
diff --git a/mysql-test/r/binlog_row_mix_innodb_myisam.result b/mysql-test/r/binlog_row_mix_innodb_myisam.result
index 078a95d5abd..84959684c42 100644
--- a/mysql-test/r/binlog_row_mix_innodb_myisam.result
+++ b/mysql-test/r/binlog_row_mix_innodb_myisam.result
@@ -234,8 +234,6 @@ commit;
begin;
create temporary table ti (a int) engine=innodb;
rollback;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
insert into ti values(1);
set autocommit=0;
create temporary table t1 (a int) engine=myisam;
@@ -285,6 +283,162 @@ master-bin.000001 1260 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 1294 Query 1 # use `test`; create table t2 (n int) engine=innodb
do release_lock("lock1");
drop table t0,t2;
+set autocommit=0;
+CREATE TABLE t1 (a int, b int) engine=myisam;
+reset master;
+INSERT INTO t1 values (1,1),(1,2);
+CREATE TABLE t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+DROP TABLE if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+INSERT INTO t1 values (3,3);
+CREATE TEMPORARY TABLE t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+DROP TABLE IF EXISTS t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb;
+INSERT INTO t1 VALUES (4,4);
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+TRUNCATE table t2;
+INSERT INTO t1 VALUES (5,5);
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * FROM t2;
+a b
+DROP TABLE t2;
+INSERT INTO t1 values (6,6);
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)) engine=innodb ;
+INSERT INTO t1 values (7,7);
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+INSERT INTO t1 values (8,8);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+COMMIT;
+INSERT INTO t1 values (9,9);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+SELECT * from t2;
+a b
+TRUNCATE table t2;
+INSERT INTO t1 values (10,10);
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t1;
+a b
+1 1
+1 2
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 9
+10 10
+INSERT INTO t2 values (100,100);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+COMMIT;
+INSERT INTO t2 values (101,101);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+SELECT * from t2;
+a b
+100 100
+DROP TABLE t1,t2;
+show binlog events from 102;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 102 Table_map 1 142 table_id: # (test.t1)
+master-bin.000001 142 Write_rows 1 189 table_id: # flags: STMT_END_F
+master-bin.000001 189 Query 1 257 use `test`; BEGIN
+master-bin.000001 257 Query 1 182 use `test`; CREATE TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 439 Table_map 1 222 table_id: # (test.t2)
+master-bin.000001 479 Write_rows 1 260 table_id: # flags: STMT_END_F
+master-bin.000001 517 Xid 1 544 COMMIT /* xid= */
+master-bin.000001 544 Query 1 630 use `test`; DROP TABLE if exists t2
+master-bin.000001 630 Table_map 1 670 table_id: # (test.t1)
+master-bin.000001 670 Write_rows 1 708 table_id: # flags: STMT_END_F
+master-bin.000001 708 Query 1 776 use `test`; BEGIN
+master-bin.000001 776 Query 1 192 use `test`; CREATE TEMPORARY TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 968 Query 1 1039 use `test`; ROLLBACK
+master-bin.000001 1039 Query 1 1125 use `test`; DROP TABLE IF EXISTS t2
+master-bin.000001 1125 Query 1 1249 use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb
+master-bin.000001 1249 Table_map 1 1289 table_id: # (test.t1)
+master-bin.000001 1289 Write_rows 1 1327 table_id: # flags: STMT_END_F
+master-bin.000001 1327 Query 1 1395 use `test`; BEGIN
+master-bin.000001 1395 Query 1 182 use `test`; CREATE TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 1577 Table_map 1 222 table_id: # (test.t2)
+master-bin.000001 1617 Write_rows 1 260 table_id: # flags: STMT_END_F
+master-bin.000001 1655 Xid 1 1682 COMMIT /* xid= */
+master-bin.000001 1682 Query 1 80 use `test`; TRUNCATE table t2
+master-bin.000001 1762 Xid 1 1789 COMMIT /* xid= */
+master-bin.000001 1789 Table_map 1 1829 table_id: # (test.t1)
+master-bin.000001 1829 Write_rows 1 1867 table_id: # flags: STMT_END_F
+master-bin.000001 1867 Query 1 1935 use `test`; BEGIN
+master-bin.000001 1935 Table_map 1 40 table_id: # (test.t2)
+master-bin.000001 1975 Write_rows 1 78 table_id: # flags: STMT_END_F
+master-bin.000001 2013 Xid 1 2040 COMMIT /* xid= */
+master-bin.000001 2040 Query 1 2116 use `test`; DROP TABLE t2
+master-bin.000001 2116 Table_map 1 2156 table_id: # (test.t1)
+master-bin.000001 2156 Write_rows 1 2194 table_id: # flags: STMT_END_F
+master-bin.000001 2194 Table_map 1 2234 table_id: # (test.t1)
+master-bin.000001 2234 Write_rows 1 2272 table_id: # flags: STMT_END_F
+master-bin.000001 2272 Table_map 1 2312 table_id: # (test.t1)
+master-bin.000001 2312 Write_rows 1 2350 table_id: # flags: STMT_END_F
+master-bin.000001 2350 Query 1 2418 use `test`; BEGIN
+master-bin.000001 2418 Query 1 192 use `test`; CREATE TEMPORARY TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 2610 Xid 1 2637 COMMIT /* xid= */
+master-bin.000001 2637 Table_map 1 2677 table_id: # (test.t1)
+master-bin.000001 2677 Write_rows 1 2715 table_id: # flags: STMT_END_F
+master-bin.000001 2715 Query 1 2783 use `test`; BEGIN
+master-bin.000001 2783 Query 1 192 use `test`; CREATE TEMPORARY TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 2975 Query 1 3046 use `test`; ROLLBACK
+master-bin.000001 3046 Query 1 80 use `test`; TRUNCATE table t2
+master-bin.000001 3126 Xid 1 3153 COMMIT /* xid= */
+master-bin.000001 3153 Table_map 1 3193 table_id: # (test.t1)
+master-bin.000001 3193 Write_rows 1 3231 table_id: # flags: STMT_END_F
+master-bin.000001 3231 Query 1 3299 use `test`; BEGIN
+master-bin.000001 3299 Query 1 192 use `test`; CREATE TEMPORARY TABLE `t2` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB
+master-bin.000001 3491 Xid 1 3518 COMMIT /* xid= */
+master-bin.000001 3518 Query 1 3622 use `test`; DROP TABLE `t1` /* generated by server */
reset master;
create table t1 (a int) engine=innodb;
create table t2 (a int) engine=myisam;
diff --git a/mysql-test/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/r/binlog_stm_mix_innodb_myisam.result
index c5abcff4246..e836cae0b15 100644
--- a/mysql-test/r/binlog_stm_mix_innodb_myisam.result
+++ b/mysql-test/r/binlog_stm_mix_innodb_myisam.result
@@ -209,8 +209,6 @@ commit;
begin;
create temporary table ti (a int) engine=innodb;
rollback;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
insert into ti values(1);
set autocommit=0;
create temporary table t1 (a int) engine=myisam;
@@ -256,6 +254,107 @@ master-bin.000001 1654 Query 1 # use `test`; create table t2 (n int) engine=inno
master-bin.000001 1754 Query 1 # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti`
do release_lock("lock1");
drop table t0,t2;
+set autocommit=0;
+CREATE TABLE t1 (a int, b int) engine=myisam;
+reset master;
+INSERT INTO t1 values (1,1),(1,2);
+CREATE TABLE t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+DROP TABLE if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+INSERT INTO t1 values (3,3);
+CREATE TEMPORARY TABLE t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+DROP TABLE IF EXISTS t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb;
+INSERT INTO t1 VALUES (4,4);
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+TRUNCATE table t2;
+INSERT INTO t1 VALUES (5,5);
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * FROM t2;
+a b
+DROP TABLE t2;
+INSERT INTO t1 values (6,6);
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)) engine=innodb ;
+INSERT INTO t1 values (7,7);
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+INSERT INTO t1 values (8,8);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+COMMIT;
+INSERT INTO t1 values (9,9);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+SELECT * from t2;
+a b
+TRUNCATE table t2;
+INSERT INTO t1 values (10,10);
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t1;
+a b
+1 1
+1 2
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 9
+10 10
+INSERT INTO t2 values (100,100);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+COMMIT;
+INSERT INTO t2 values (101,101);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+ROLLBACK;
+SELECT * from t2;
+a b
+100 100
+DROP TABLE t1,t2;
+show binlog events from 102;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 102 Query 1 198 use `test`; INSERT INTO t1 values (1,1),(1,2)
+master-bin.000001 198 Query 1 284 use `test`; DROP TABLE if exists t2
+master-bin.000001 284 Query 1 374 use `test`; INSERT INTO t1 values (3,3)
+master-bin.000001 374 Query 1 460 use `test`; DROP TABLE IF EXISTS t2
+master-bin.000001 460 Query 1 584 use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb
+master-bin.000001 584 Query 1 674 use `test`; INSERT INTO t1 VALUES (4,4)
+master-bin.000001 674 Query 1 80 use `test`; TRUNCATE table t2
+master-bin.000001 754 Xid 1 781 COMMIT /* xid= */
+master-bin.000001 781 Query 1 871 use `test`; INSERT INTO t1 VALUES (5,5)
+master-bin.000001 871 Query 1 947 use `test`; DROP TABLE t2
+master-bin.000001 947 Query 1 1037 use `test`; INSERT INTO t1 values (6,6)
+master-bin.000001 1037 Query 1 1171 use `test`; CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)) engine=innodb
+master-bin.000001 1171 Query 1 1261 use `test`; INSERT INTO t1 values (7,7)
+master-bin.000001 1261 Query 1 1351 use `test`; INSERT INTO t1 values (8,8)
+master-bin.000001 1351 Query 1 1441 use `test`; INSERT INTO t1 values (9,9)
+master-bin.000001 1441 Query 1 80 use `test`; TRUNCATE table t2
+master-bin.000001 1521 Xid 1 1548 COMMIT /* xid= */
+master-bin.000001 1548 Query 1 1640 use `test`; INSERT INTO t1 values (10,10)
+master-bin.000001 1640 Query 1 1708 use `test`; BEGIN
+master-bin.000001 1708 Query 1 94 use `test`; INSERT INTO t2 values (100,100)
+master-bin.000001 1802 Xid 1 1829 COMMIT /* xid= */
+master-bin.000001 1829 Query 1 1908 use `test`; DROP TABLE t1,t2
reset master;
create table t1 (a int) engine=innodb;
create table t2 (a int) engine=myisam;
diff --git a/mysql-test/r/compress.result b/mysql-test/r/compress.result
index efcafbbe736..691bd56474b 100644
--- a/mysql-test/r/compress.result
+++ b/mysql-test/r/compress.result
@@ -145,9 +145,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index
explain select fld3 from t2 ignore index (fld3,not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
explain select fld3 from t2 use index (not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
fld3
honeysuckle
diff --git a/mysql-test/r/contributors.result b/mysql-test/r/contributors.result
new file mode 100644
index 00000000000..5739c2244c3
--- /dev/null
+++ b/mysql-test/r/contributors.result
@@ -0,0 +1,5 @@
+SHOW CONTRIBUTORS;
+Name Location Comment
+Ronald Bradford Brisbane, Australia EFF contribution for UC2006 Auction
+Sheeri Kritzer Boston, Mass. USA EFF contribution for UC2006 Auction
+Mark Shuttleworth London, UK. EFF contribution for UC2006 Auction
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 41baeedf3f8..c3710865b15 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -266,6 +266,7 @@ select * from t1;
0 1 2
0 0 1
drop table t1;
+flush status;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
@@ -281,6 +282,13 @@ Warnings:
Note 1050 Table 't1' already exists
create table if not exists t1 select 3 as 'a',3 as 'b';
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
+show warnings;
+Level Code Message
+Note 1050 Table 't1' already exists
+Error 1062 Duplicate entry '3' for key 'PRIMARY'
+show status like "Opened_tables";
+Variable_name Value
+Opened_tables 2
select * from t1;
a b
1 1
@@ -772,3 +780,41 @@ t1 CREATE TABLE `t1` (
`i` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=4294967295
drop table t1;
+CREATE TABLE t1 (a int, b int);
+insert into t1 values (1,1),(1,2);
+CREATE TABLE t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+drop table if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+drop table if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TABLE t2 (a int, b int, primary key (a));
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+1 1
+TRUNCATE table t2;
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+1 1
+drop table t2;
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a));
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+1 1
+TRUNCATE table t2;
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+1 1
+drop table t1,t2;
diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result
index eaea2e7479a..1c9d540d574 100644
--- a/mysql-test/r/ctype_sjis.result
+++ b/mysql-test/r/ctype_sjis.result
@@ -172,6 +172,6 @@ c2h
ab_def
drop table t1;
SET NAMES sjis;
-SELECT HEX('²“‘@\Œ\') FROM DUAL;
-HEX('²“‘@_Œ\')
+SELECT HEX('²“‘@Œ\') FROM DUAL;
+HEX('²“‘@Œ\')
8DB2939181408C5C
diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result
index 01d206be7cb..77280f99b7c 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -17,13 +17,13 @@ db_x
SHOW TABLES FROM db_x;
Tables_in_db_x
x_table
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
DROP EVENT e_x1;
DROP EVENT e_x2;
DROP DATABASE db_x;
DROP USER pauline@localhost;
USE events_test;
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
@@ -100,7 +100,7 @@ a
800219
drop event non_qualif_ev;
drop table non_qualif;
-set global event_scheduler = 0;
+set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
@@ -254,7 +254,7 @@ event CREATE TABLE `event` (
`on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP',
`sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '',
`comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
- PRIMARY KEY (`definer`,`db`,`name`)
+ PRIMARY KEY (`db`,`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
@@ -280,87 +280,6 @@ SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED
DROP EVENT intact_check;
-create event one_event on schedule every 10 second do select 123;
-SHOW EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
-SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
-EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
-NULL events_test one_event root@localhost select 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
-CREATE DATABASE events_test2;
-CREATE USER ev_test@localhost;
-GRANT ALL ON events_test.* to ev_test@localhost;
-GRANT ALL on events_test2.* to ev_test@localhost;
-REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
-REVOKE PROCESS on *.* from ev_test@localhost;
-select "NEW CONNECTION";
-NEW CONNECTION
-NEW CONNECTION
-SELECT USER(), DATABASE();
-USER() DATABASE()
-ev_test@localhost events_test2
-SHOW GRANTS;
-Grants for ev_test@localhost
-GRANT USAGE ON *.* TO 'ev_test'@'localhost'
-GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost'
-GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER ON `events_test2`.* TO 'ev_test'@'localhost'
-"Here comes an error:";
-SHOW EVENTS;
-ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2'
-USE events_test;
-"Now the list should be empty:";
-SHOW EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-select concat("Let's create some new events from the name of ",user());
-concat("Let's create some new events from the name of ",user())
-Let's create some new events from the name of ev_test@localhost
-create event one_event on schedule every 20 second do select 123;
-create event two_event on schedule every 20 second on completion not preserve comment "two event" do select 123;
-create event three_event on schedule every 20 second on completion preserve comment "three event" do select 123;
-"Now we should see 3 events:";
-SHOW EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-"This should show us only 3 events:";
-SHOW FULL EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-"This should show us only 2 events:";
-SHOW FULL EVENTS LIKE 't%event';
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-"This should show us no events:";
-SHOW FULL EVENTS FROM test LIKE '%';
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-DROP DATABASE events_test2;
-"should see 1 event:";
-SHOW EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
-"we should see 4 events now:";
-SHOW FULL EVENTS;
-Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
-events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
-events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
-SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
-EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
-NULL events_test one_event ev_test@localhost select 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE
-NULL events_test three_event ev_test@localhost select 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
-NULL events_test two_event ev_test@localhost select 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
-NULL events_test one_event root@localhost select 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
-drop event one_event;
-drop event two_event;
-drop event three_event;
-drop user ev_test@localhost;
-drop event one_event;
-"Sleep a bit so the server closes the second connection"
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
@@ -373,12 +292,12 @@ ERROR HY000: Incorrect AT value: 'definitely not a datetime'
set names utf8;
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
drop event задачка;
-set event_scheduler=0;
+set event_scheduler=2;
ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL
-set global event_scheduler=2;
-ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2'
+set global event_scheduler=3;
+ERROR 42000: Variable 'event_scheduler' can't be set to the value of '3'
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
-set global event_scheduler=0;
+set global event_scheduler=2;
select definer, name, db from mysql.event;
definer name db
select get_lock("test_lock1", 20);
@@ -389,9 +308,10 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
select definer, name, db from mysql.event;
definer name db
root@localhost закачка events_test
-"Should be 0 processes"
+"Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
+event_scheduler localhost NULL Connect Suspended NULL
select release_lock("test_lock1");
release_lock("test_lock1")
1
@@ -409,11 +329,12 @@ get_lock("test_lock2", 20)
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
"Let some time pass to the event starts"
"Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
+"Release the mutex, the event worker should finish."
select release_lock("test_lock2");
release_lock("test_lock2")
1
@@ -423,21 +344,17 @@ select get_lock("test_lock2_1", 20);
get_lock("test_lock2_1", 20)
1
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
-"Should see 1 process, locked on get_lock("
-"Shutting down the scheduler, it should wait for the running event"
-set global event_scheduler=0;
-"Should have only 2 processes: the scheduler and the locked event"
-select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+"Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
-"Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
-release_lock("test_lock2_1")
-1
-"Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+set global event_scheduler=2;
+"Should have only our process now:"
+select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
+event_scheduler localhost NULL Connect Suspended NULL
+root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result
index ef1ccfadecb..bc89c692f9a 100644
--- a/mysql-test/r/events_bugs.result
+++ b/mysql-test/r/events_bugs.result
@@ -35,7 +35,7 @@ create event e_55 on schedule every 10 hour starts 99990101000000 do drop table
ERROR HY000: Incorrect STARTS value: '99990101000000'
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
ERROR HY000: ENDS is either invalid or before STARTS
-set global event_scheduler=0;
+set global event_scheduler=2;
"Wait a bit to settle down"
delete from mysql.event;
set global event_scheduler= 1;
@@ -57,7 +57,7 @@ root localhost events_test Connect User lock select get_lock('test_bug16407', 60
select release_lock('test_bug16407');
release_lock('test_bug16407')
1
-set global event_scheduler= 0;
+set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
event_schema event_name sql_mode
events_test e_16407 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
@@ -115,7 +115,7 @@ release_lock('ee_16407_2')
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
-set global event_scheduler= 0;
+set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
ev_name a
ee_16407_3 1980-02-19
@@ -175,7 +175,7 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
-set global event_scheduler= 0;
+set global event_scheduler= 2;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
drop database events_test;
diff --git a/mysql-test/r/events_grant.result b/mysql-test/r/events_grant.result
new file mode 100644
index 00000000000..6c140f91eaa
--- /dev/null
+++ b/mysql-test/r/events_grant.result
@@ -0,0 +1,121 @@
+CREATE DATABASE IF NOT EXISTS events_test;
+use events_test;
+CREATE EVENT one_event ON SCHEDULE EVERY 10 SECOND DO SELECT 123;
+SHOW EVENTS;
+Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
+events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+CREATE DATABASE events_test2;
+CREATE USER ev_test@localhost;
+GRANT ALL ON events_test.* to ev_test@localhost;
+GRANT ALL ON events_test2.* to ev_test@localhost;
+REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
+select "NEW CONNECTION";
+NEW CONNECTION
+NEW CONNECTION
+SELECT USER(), DATABASE();
+USER() DATABASE()
+ev_test@localhost events_test2
+SHOW GRANTS;
+Grants for ev_test@localhost
+GRANT USAGE ON *.* TO 'ev_test'@'localhost'
+GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost'
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER ON `events_test2`.* TO 'ev_test'@'localhost'
+"Here comes an error:";
+SHOW EVENTS;
+ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2'
+USE events_test;
+"We should see one event";
+SHOW EVENTS;
+Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
+events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
+SELECT CONCAT("Let's create some new events from the name of ", USER());
+CONCAT("Let's create some new events from the name of ", USER())
+Let's create some new events from the name of ev_test@localhost
+CREATE EVENT one_event ON SCHEDULE EVERY 20 SECOND DO SELECT 123;
+ERROR HY000: Event 'one_event' already exists
+CREATE EVENT two_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION NOT PRESERVE COMMENT "two event" DO SELECT 123;
+CREATE EVENT three_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION PRESERVE COMMENT "three event" DO SELECT 123;
+"Now we should see 3 events:";
+SHOW EVENTS;
+Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
+events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
+events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
+events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
+"This should show us only 2 events:";
+SHOW EVENTS LIKE 't%event';
+Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
+events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
+events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
+"This should show us no events:";
+SHOW EVENTS FROM test LIKE '%';
+Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
+GRANT EVENT ON events_test2.* TO ev_test@localhost;
+USE events_test2;
+CREATE EVENT four_event ON SCHEDULE EVERY 20 SECOND DO SELECT 42;
+USE events_test;
+"We should see 4 events : one_event, two_event, three_event & four_event"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+NULL events_test two_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
+NULL events_test three_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
+NULL events_test2 four_event ev_test@localhost SELECT 42 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE
+DROP DATABASE events_test2;
+"We should see 3 events : one_event, two_event, three_event"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+NULL events_test two_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
+NULL events_test three_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
+CREATE DATABASE events_test2;
+USE events_test2;
+CREATE EVENT five_event ON SCHEDULE EVERY 20 SECOND DO SELECT 42;
+"Should see 4 events - one, two, three & five"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+NULL events_test two_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
+NULL events_test three_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
+NULL events_test2 five_event root@localhost SELECT 42 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE
+REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
+USE test;
+"Should see 3 events - one, two & three"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+NULL events_test two_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
+NULL events_test three_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
+"Let's test ALTER EVENT which changes the definer"
+USE events_test;
+ALTER EVENT one_event ON SCHEDULE EVERY 10 SECOND;
+"The definer should be ev_test@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event ev_test@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE
+USE events_test;
+ALTER EVENT one_event COMMENT "comment";
+"The definer should be root@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event root@localhost SELECT 123 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE comment
+ALTER EVENT one_event DO SELECT 12;
+"The definer should be ev_test@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test one_event ev_test@localhost SELECT 12 RECURRING NULL 10 SECOND ENABLED NOT PRESERVE comment
+"make the definer again root@localhost"
+ALTER EVENT one_event COMMENT "new comment";
+"test DROP by another user"
+DROP EVENT one_event;
+"One event should not be there"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
+NULL events_test two_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event
+NULL events_test three_event ev_test@localhost SELECT 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event
+NULL events_test2 five_event root@localhost SELECT 42 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE
+DROP USER ev_test@localhost;
+DROP DATABASE events_test2;
+DROP DATABASE events_test;
diff --git a/mysql-test/r/events_logs_tests.result b/mysql-test/r/events_logs_tests.result
index ab1666fefb9..ce58e0ec059 100644
--- a/mysql-test/r/events_logs_tests.result
+++ b/mysql-test/r/events_logs_tests.result
@@ -8,7 +8,7 @@ BEGIN
SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
END|
"Check General Query Log"
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
TRUNCATE mysql.general_log;
"1 row, the current statement!"
@@ -19,10 +19,10 @@ SET GLOBAL event_scheduler=1;
"Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
call select_general_log();
user_host argument
-root[root] @ localhost [localhost] SELect 'alabala', sleep(3) from dual
+USER_HOST SELect 'alabala', sleep(3) from dual
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
"Check slow query log"
"Save the values"
SET @old_global_long_query_time:=(select get_value());
@@ -36,14 +36,14 @@ SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"Set new values"
SET GLOBAL long_query_time=4;
-SET SESSION long_query_time=2;
+SET SESSION long_query_time=1;
"Check that logging is working"
-SELECT SLEEP(3);
-SLEEP(3)
+SELECT SLEEP(2);
+SLEEP(2)
0
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
-root[root] @ localhost [] SLEEPVAL events_test SELECT SLEEP(3)
+USER_HOST SLEEPVAL events_test SELECT SLEEP(2)
TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
"This won't go to the slow log"
@@ -54,7 +54,7 @@ SET GLOBAL event_scheduler=1;
"Sleep some more time than the actual event run will take"
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
-event_scheduler ON
+event_scheduler 1
"Check our table. Should see 1 row"
SELECT * FROM slow_event_test;
slo_val val
@@ -64,18 +64,19 @@ SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"This should go to the slow log"
SET SESSION long_query_time=10;
+SET GLOBAL long_query_time=1;
DROP EVENT long_event;
-CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5);
+CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
"Sleep some more time than the actual event run will take"
"Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
slo_val val
4 0
-4 0
-"Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
+1 0
+"Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
-root[root] @ localhost [localhost] SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5)
+USER_HOST SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2)
DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;
diff --git a/mysql-test/r/events_microsec.result b/mysql-test/r/events_microsec.result
index ed15b066b93..b96bd551511 100644
--- a/mysql-test/r/events_microsec.result
+++ b/mysql-test/r/events_microsec.result
@@ -10,50 +10,4 @@ CREATE EVENT micro_test ON SCHEDULE EVERY 100 MINUTE_MICROSECOND DO SELECT 1;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
CREATE EVENT micro_test ON SCHEDULE EVERY 100 SECOND_MICROSECOND DO SELECT 1;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-"Now create normal event and change it on SQL level"
-CREATE EVENT micro_test2 ON SCHEDULE EVERY 1 MONTH DO SELECT 1;
-UPDATE mysql.event SET interval_field='MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
-SHOW CREATE EVENT micro_test2;
-ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-SET GLOBAL event_scheduler=0;
-"Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-Variable_name Value
-event_scheduler OFF
-UPDATE mysql.event SET interval_field='DAY_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
-SHOW CREATE EVENT micro_test2;
-ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-SET GLOBAL event_scheduler=0;
-"Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-Variable_name Value
-event_scheduler OFF
-UPDATE mysql.event SET interval_field='SECOND_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
-SHOW CREATE EVENT micro_test2;
-ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-SET GLOBAL event_scheduler=0;
-"Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-Variable_name Value
-event_scheduler OFF
-UPDATE mysql.event SET interval_field='HOUR_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
-SHOW CREATE EVENT micro_test2;
-ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-SET GLOBAL event_scheduler=0;
-"Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-Variable_name Value
-event_scheduler OFF
-UPDATE mysql.event SET interval_field='MINUTE_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
-SHOW CREATE EVENT micro_test2;
-ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
-SET GLOBAL event_scheduler=0;
-"Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-Variable_name Value
-event_scheduler OFF
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='event_scheduler';
-COUNT(*)
-0
-DROP EVENT micro_test2;
drop database events_test;
diff --git a/mysql-test/r/events_scheduling.result b/mysql-test/r/events_scheduling.result
index 8b1f29d320f..eb44751c176 100644
--- a/mysql-test/r/events_scheduling.result
+++ b/mysql-test/r/events_scheduling.result
@@ -6,7 +6,7 @@ CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1;
-CREATE EVENT E19170 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
+CREATE EVENT E19170 ON SCHEDULE EVERY 2 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND
@@ -14,7 +14,7 @@ ENDS NOW() + INTERVAL 6 SECOND
ON COMPLETION PRESERVE
DO INSERT INTO table_2 VALUES(1);
CREATE EVENT only_one_time ON SCHEDULE EVERY 2 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_3 VALUES(1);
-CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_4 VALUES(1);
+CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND ON COMPLETION PRESERVE DO INSERT INTO table_4 VALUES(1);
SELECT IF(SUM(a) >= 4, 'OK', 'ERROR') FROM table_1;
IF(SUM(a) >= 4, 'OK', 'ERROR')
OK
@@ -38,9 +38,12 @@ DROP EVENT start_n_end;
"Already dropped because ended. Therefore an error."
DROP EVENT only_one_time;
ERROR HY000: Unknown event 'only_one_time'
-"Already dropped because ended. Therefore an error."
+"Should be preserved"
+SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
+EVENT_NAME STATUS
+E19170 ENABLED
+two_time DISABLED
DROP EVENT two_time;
-ERROR HY000: Unknown event 'two_time'
DROP TABLE table_1;
DROP TABLE table_2;
DROP TABLE table_3;
diff --git a/mysql-test/r/events_stress.result b/mysql-test/r/events_stress.result
index 9f95cfad75d..ead618e8136 100644
--- a/mysql-test/r/events_stress.result
+++ b/mysql-test/r/events_stress.result
@@ -1,46 +1,61 @@
CREATE DATABASE IF NOT EXISTS events_test;
-CREATE DATABASE events_test2;
-USE events_test2;
+CREATE DATABASE events_conn1_test2;
+CREATE TABLE events_test.fill_it(test_name varchar(20), occur datetime);
+CREATE USER event_user2@localhost;
+CREATE DATABASE events_conn2_db;
+GRANT ALL ON *.* TO event_user2@localhost;
+CREATE USER event_user3@localhost;
+CREATE DATABASE events_conn3_db;
+GRANT ALL ON *.* TO event_user3@localhost;
+"In the second connection we create some events which won't be dropped till the end"
+"In the second connection we create some events which won't be dropped till the end"
+USE events_conn1_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS;
+COUNT(*)
+103
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
3
-DROP DATABASE events_test2;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+DROP DATABASE events_conn1_test2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
0
"Now testing stability - dropping db -> events while they are running"
-CREATE DATABASE events_test2;
-USE events_test2;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+CREATE DATABASE events_conn1_test2;
+USE events_conn1_test2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
-1000
+50
SET GLOBAL event_scheduler=1;
-DROP DATABASE events_test2;
-SET GLOBAL event_scheduler=0;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+DROP DATABASE events_conn1_test2;
+SET GLOBAL event_scheduler=2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
0
-CREATE DATABASE events_test3;
-USE events_test3;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
+CREATE DATABASE events_conn1_test3;
+USE events_conn1_test3;
+SET GLOBAL event_scheduler=1;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
COUNT(*)
-950
-CREATE DATABASE events_test4;
-USE events_test4;
-CREATE DATABASE events_test2;
-USE events_test2;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+50
+CREATE DATABASE events_conn1_test4;
+USE events_conn1_test4;
+CREATE DATABASE events_conn1_test2;
+USE events_conn1_test2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
-1050
-DROP DATABASE events_test2;
-SET GLOBAL event_scheduler=0;
-DROP DATABASE events_test3;
-SET GLOBAL event_scheduler=1;
-DROP DATABASE events_test4;
+50
+DROP DATABASE events_conn2_db;
+DROP DATABASE events_conn3_db;
+DROP DATABASE events_conn1_test2;
+DROP DATABASE events_conn1_test3;
+SET GLOBAL event_scheduler=2;
+DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
USE events_test;
+DROP TABLE fill_it;
DROP DATABASE events_test;
diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result
index 75e1548cdee..e0d9f5131b4 100644
--- a/mysql-test/r/explain.result
+++ b/mysql-test/r/explain.result
@@ -24,9 +24,9 @@ explain select * from t1 use key (str,str) where str="foo";
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const str str 11 const 1
explain select * from t1 use key (str,str,foo) where str="foo";
-ERROR 42000: Key column 'foo' doesn't exist in table
+ERROR 42000: Key 'foo' doesn't exist in table 't1'
explain select * from t1 ignore key (str,str,foo) where str="foo";
-ERROR 42000: Key column 'foo' doesn't exist in table
+ERROR 42000: Key 'foo' doesn't exist in table 't1'
drop table t1;
explain select 1;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result
index 5f735ebe926..b3d6e10448b 100644
--- a/mysql-test/r/federated.result
+++ b/mysql-test/r/federated.result
@@ -1601,6 +1601,7 @@ fld_cid fld_name fld_parentid fld_delt
5 Torkel 0 0
DROP TABLE federated.t1;
DROP TABLE federated.bug_17377_table;
+DROP TABLE federated.t1;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1;
diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result
index 16c308e3450..a7f5e5e8fec 100644
--- a/mysql-test/r/flush.result
+++ b/mysql-test/r/flush.result
@@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read;
flush tables with read lock;
unlock tables;
drop table t1, t2, t3;
+create table t1 (c1 int);
+create table t2 (c1 int);
+lock table t1 write;
+ flush tables with read lock;
+ insert into t2 values(1);
+unlock tables;
+drop table t1, t2;
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index 62b4ddf868a..773efe50749 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -309,6 +309,12 @@ a grp
1 2
2 4,3
3 5
+select group_concat(c order by (select concat(5-t1.c,group_concat(c order by a)) from t2 where t2.a=t1.a)) as grp from t1;
+grp
+5,4,3,2
+select group_concat(c order by (select concat(t1.c,group_concat(c)) from t2 where a=t1.a)) as grp from t1;
+grp
+2,3,4,5
select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp;
a c grp
3 5 3,3
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index e3257ce5fd0..e38e2624e19 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -326,3 +326,20 @@ deallocate prepare s;
set @str=NULL;
drop table t2;
drop table t1;
+create table t1 (
+some_id smallint(5) unsigned,
+key (some_id)
+);
+insert into t1 values (1),(2);
+select some_id from t1 where some_id not in(2,-1);
+some_id
+1
+select some_id from t1 where some_id not in(-4,-1,-4);
+some_id
+1
+2
+select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
+some_id
+1
+2
+drop table t1;
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 960a5178fd8..354c886b19b 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1046,4 +1046,10 @@ cast(ltrim(' 20.06 ') as decimal(19,2))
select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2));
cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2))
20.06
+select conv("18383815659218730760",10,10) + 0;
+conv("18383815659218730760",10,10) + 0
+1.8383815659219e+19
+select "18383815659218730760" + 0;
+"18383815659218730760" + 0
+1.8383815659219e+19
End of 5.0 tests
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 516809b8906..283dd11ca1e 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -763,6 +763,7 @@ time_format('100:00:00', '%H %k %h %I %l')
100 100 04 04 4
create table t1 (a timestamp default '2005-05-05 01:01:01',
b timestamp default '2005-05-05 01:01:01');
+drop function if exists t_slow_sysdate;
create function t_slow_sysdate() returns timestamp
begin
do sleep(2);
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index 4815798d807..82775f0735b 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -357,12 +357,12 @@ show grants for grant_user@localhost;
Grants for grant_user@localhost
GRANT USAGE ON *.* TO 'grant_user'@'localhost'
GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost'
-select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv;
+select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name;
Host Db User Table_name Column_name Column_priv
-localhost test grant_user t1 b Insert
-localhost test grant_user t1 d Insert
localhost test grant_user t1 a Insert
+localhost test grant_user t1 b Insert
localhost test grant_user t1 c Insert
+localhost test grant_user t1 d Insert
revoke ALL PRIVILEGES on t1 from grant_user@localhost;
show grants for grant_user@localhost;
Grants for grant_user@localhost
@@ -381,13 +381,27 @@ grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost;
grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost;
grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost;
grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost;
-show grants for mysqltest_3@localhost;
-Grants for mysqltest_3@localhost
-GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost'
-GRANT SELECT (b) ON `mysqltest_1`.`t2` TO 'mysqltest_3'@'localhost'
-GRANT UPDATE (a) ON `mysqltest_1`.`t1` TO 'mysqltest_3'@'localhost'
-GRANT UPDATE (d) ON `mysqltest_2`.`t2` TO 'mysqltest_3'@'localhost'
-GRANT SELECT (c) ON `mysqltest_2`.`t1` TO 'mysqltest_3'@'localhost'
+SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES
+WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_3'@'localhost' NULL mysqltest_1 t1 a UPDATE NO
+'mysqltest_3'@'localhost' NULL mysqltest_2 t1 c SELECT NO
+'mysqltest_3'@'localhost' NULL mysqltest_1 t2 b SELECT NO
+'mysqltest_3'@'localhost' NULL mysqltest_2 t2 d UPDATE NO
+SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
+WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ORDER BY TABLE_NAME,PRIVILEGE_TYPE;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
+SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES
+WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE
+SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES
+WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE;
+GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_3'@'localhost' NULL USAGE NO
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'q' in table 't1'
update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1;
@@ -593,6 +607,7 @@ insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_gr
flush privileges;
delete from tables_priv where host = '' and user = 'mysqltest_1';
flush privileges;
+use test;
set @user123="non-existent";
select * from mysql.db where user=@user123;
Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv
@@ -623,7 +638,6 @@ show grants for mysqltest_7@;
Grants for mysqltest_7@
GRANT USAGE ON *.* TO 'mysqltest_7'@'' IDENTIFIED BY PASSWORD '*2FB071A056F9BB745219D9C876814231DAF46517'
drop user mysqltest_7@;
-flush privileges;
show grants for mysqltest_7@;
ERROR 42000: There is no such grant defined for user 'mysqltest_7' on host ''
create database mysqltest;
@@ -644,3 +658,214 @@ delete from mysql.db where user='mysqltest1';
delete from mysql.tables_priv where user='mysqltest1';
flush privileges;
drop database mysqltest;
+use test;
+create table t1 (a int);
+create table t2 as select * from mysql.user where user='';
+delete from mysql.user where user='';
+flush privileges;
+create user mysqltest_8@'';
+create user mysqltest_8;
+create user mysqltest_8@host8;
+create user mysqltest_8@'';
+ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@''
+create user mysqltest_8;
+ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@'%'
+create user mysqltest_8@host8;
+ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@'host8'
+select user, QUOTE(host) from mysql.user where user="mysqltest_8";
+user QUOTE(host)
+mysqltest_8 ''
+mysqltest_8 '%'
+mysqltest_8 'host8'
+Schema privileges
+grant select on mysqltest.* to mysqltest_8@'';
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@''
+grant select on mysqltest.* to mysqltest_8@;
+show grants for mysqltest_8@;
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@''
+grant select on mysqltest.* to mysqltest_8;
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@'%'
+select * from information_schema.schema_privileges
+where grantee like "'mysqltest_8'%";
+GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_8'@'%' NULL mysqltest SELECT NO
+'mysqltest_8'@'' NULL mysqltest SELECT NO
+select * from t1;
+a
+revoke select on mysqltest.* from mysqltest_8@'';
+revoke select on mysqltest.* from mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+select * from information_schema.schema_privileges
+where grantee like "'mysqltest_8'%";
+GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8@;
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+grant select on mysqltest.* to mysqltest_8@'';
+flush privileges;
+show grants for mysqltest_8@;
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@''
+revoke select on mysqltest.* from mysqltest_8@'';
+flush privileges;
+Column privileges
+grant update (a) on t1 to mysqltest_8@'';
+grant update (a) on t1 to mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'%'
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'%'
+select * from information_schema.column_privileges;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_8'@'%' NULL test t1 a UPDATE NO
+'mysqltest_8'@'' NULL test t1 a UPDATE NO
+select * from t1;
+a
+revoke update (a) on t1 from mysqltest_8@'';
+revoke update (a) on t1 from mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+select * from information_schema.column_privileges;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+Table privileges
+grant update on t1 to mysqltest_8@'';
+grant update on t1 to mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'%'
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'%'
+select * from information_schema.table_privileges;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_8'@'%' NULL test t1 UPDATE NO
+'mysqltest_8'@'' NULL test t1 UPDATE NO
+select * from t1;
+a
+revoke update on t1 from mysqltest_8@'';
+revoke update on t1 from mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+select * from information_schema.table_privileges;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+"DROP USER" should clear privileges
+grant all privileges on mysqltest.* to mysqltest_8@'';
+grant select on mysqltest.* to mysqltest_8@'';
+grant update on t1 to mysqltest_8@'';
+grant update (a) on t1 to mysqltest_8@'';
+grant all privileges on mysqltest.* to mysqltest_8;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@''
+GRANT UPDATE, UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%'
+select * from information_schema.user_privileges
+where grantee like "'mysqltest_8'%";
+GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_8'@'host8' NULL USAGE NO
+'mysqltest_8'@'%' NULL USAGE NO
+'mysqltest_8'@'' NULL USAGE NO
+select * from t1;
+a
+flush privileges;
+show grants for mysqltest_8@'';
+Grants for mysqltest_8@
+GRANT USAGE ON *.* TO 'mysqltest_8'@''
+GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@''
+GRANT UPDATE, UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%'
+drop user mysqltest_8@'';
+show grants for mysqltest_8@'';
+ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host ''
+show grants for mysqltest_8;
+Grants for mysqltest_8@%
+GRANT USAGE ON *.* TO 'mysqltest_8'@'%'
+GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%'
+select * from information_schema.user_privileges
+where grantee like "'mysqltest_8'%";
+GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_8'@'host8' NULL USAGE NO
+'mysqltest_8'@'%' NULL USAGE NO
+drop user mysqltest_8;
+connect(localhost,mysqltest_8,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'mysqltest_8'@'localhost' (using password: NO)
+show grants for mysqltest_8;
+ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host '%'
+drop user mysqltest_8@host8;
+show grants for mysqltest_8@host8;
+ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host 'host8'
+insert into mysql.user select * from t2;
+flush privileges;
+drop table t2;
+drop table t1;
diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result
index a37f260ff31..68b13b5fc0a 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -12,7 +12,7 @@ explain extended select count(a) as b from t1 where a=0 having b >=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
-Note 1003 select count(`test`.`t1`.`a`) AS `b` from `test`.`t1` where 0 having (count(`test`.`t1`.`a`) >= 0)
+Note 1003 select count(`test`.`t1`.`a`) AS `b` from `test`.`t1` where 0 having (`b` >= 0)
drop table t1;
CREATE TABLE t1 (
raw_id int(10) NOT NULL default '0',
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index 2c0e8123667..a75f6c96b20 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -718,3 +718,16 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I
t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL
t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL
drop table t1, t2;
+CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256),
+KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256));
+SELECT COUNT(*) FROM t1 WHERE a='a';
+COUNT(*)
+2
+SELECT COUNT(*) FROM t1 WHERE b='aa';
+COUNT(*)
+2
+SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256);
+COUNT(*)
+2
+DROP TABLE t1;
diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result
index 7b944558a62..4c7ea0eae7b 100644
--- a/mysql-test/r/heap_btree.result
+++ b/mysql-test/r/heap_btree.result
@@ -256,3 +256,6 @@ SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()
INDEX_LENGTH
21
DROP TABLE t1;
+CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES(NULL),(NULL);
+DROP TABLE t1;
diff --git a/mysql-test/r/im_cmd_line.result b/mysql-test/r/im_cmd_line.result
new file mode 100644
index 00000000000..5b289549a3f
--- /dev/null
+++ b/mysql-test/r/im_cmd_line.result
@@ -0,0 +1,40 @@
+--> Listing users...
+im_admin
+
+==> Adding user 'testuser'...
+
+--> IM password file:
+testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+--> EOF
+
+--> Printing out line for 'testuser'...
+testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
+
+--> Listing users...
+im_admin
+testuser
+
+==> Changing the password of 'testuser'...
+
+--> IM password file:
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
+--> EOF
+
+--> Printing out line for 'testuser'...
+testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
+
+--> Listing users...
+testuser
+im_admin
+
+==> Dropping user 'testuser'...
+
+--> IM password file:
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+--> EOF
+
+--> Listing users...
+im_admin
+
diff --git a/mysql-test/r/im_daemon_life_cycle.result b/mysql-test/r/im_daemon_life_cycle.result
index d0a76b450fe..29c9ea2047d 100644
--- a/mysql-test/r/im_daemon_life_cycle.result
+++ b/mysql-test/r/im_daemon_life_cycle.result
@@ -1,5 +1,5 @@
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
Killing the process...
diff --git a/mysql-test/r/im_instance_conf.result b/mysql-test/r/im_instance_conf.result
new file mode 100644
index 00000000000..efda9439f38
--- /dev/null
+++ b/mysql-test/r/im_instance_conf.result
@@ -0,0 +1,196 @@
+--------------------------------------------------------------------
+server_id = 1
+server_id = 2
+--------------------------------------------------------------------
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+
+---> connection: mysql1_con
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+
+---> connection: default
+CREATE INSTANCE mysqld3;
+SHOW INSTANCES;
+instance_name state
+mysqld3 offline
+mysqld2 offline
+mysqld1 online
+--------------------------------------------------------------------
+server_id = 1
+server_id = 2
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld1;
+ERROR HY000: Instance already exists
+CREATE INSTANCE mysqld2;
+ERROR HY000: Instance already exists
+CREATE INSTANCE mysqld3;
+ERROR HY000: Instance already exists
+--------------------------------------------------------------------
+nonguarded
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld4 nonguarded;
+SHOW INSTANCES;
+instance_name state
+mysqld3 offline
+mysqld4 offline
+mysqld1 online
+mysqld2 offline
+--------------------------------------------------------------------
+nonguarded
+nonguarded
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld4 offline
+mysqld5 offline
+mysqld2 offline
+mysqld3 offline
+--------------------------------------------------------------------
+test-A=000
+--------------------------------------------------------------------
+test-B=test
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld6 test-C1 = 10 , test-C2 = 02 ;
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+--------------------------------------------------------------------
+test-C1=10
+--------------------------------------------------------------------
+test-C2=02
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld7 test-D = test-D-value ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+CREATE INSTANCE mysqld8 test-E 0 ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+CREATE INSTANCE mysqld8 test-F = ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld9 test-1=" hello world ", test-2=' ';
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+mysqld9 offline
+CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld9a offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+mysqld9 offline
+mysqld2 offline
+CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
+SHOW INSTANCES;
+instance_name state
+mysqld9b offline
+mysqld9a offline
+mysqld5 offline
+mysqld6 offline
+mysqld3 offline
+mysqld4 offline
+mysqld9 offline
+mysqld2 offline
+mysqld1 online
+CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
+SHOW INSTANCES;
+instance_name state
+mysqld9b offline
+mysqld6 offline
+mysqld5 offline
+mysqld9c offline
+mysqld3 offline
+mysqld4 offline
+mysqld9 offline
+mysqld2 offline
+mysqld1 online
+mysqld9a offline
+CREATE INSTANCE mysqld10 test-bad=' \ ';
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name state
+mysqld9b offline
+mysqld6 offline
+mysqld5 offline
+mysqld9c offline
+mysqld3 offline
+mysqld4 offline
+mysqld9 offline
+mysqld2 offline
+mysqld1 online
+mysqld9a offline
+--------------------------------------------------------------------
+test-1= hello world
+--------------------------------------------------------------------
+test-2=
+--------------------------------------------------------------------
+test-3=abc def
+--------------------------------------------------------------------
+test-4=abc def
+--------------------------------------------------------------------
+test-5=abc
+--------------------------------------------------------------------
+test-6=abc def
+--------------------------------------------------------------------
+test-7=abc\def
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE qqq1;
+ERROR HY000: Malformed instance name.
diff --git a/mysql-test/r/im_life_cycle.result b/mysql-test/r/im_life_cycle.result
index e208ccb9f00..876fbb38eee 100644
--- a/mysql-test/r/im_life_cycle.result
+++ b/mysql-test/r/im_life_cycle.result
@@ -1,69 +1,93 @@
+
+--------------------------------------------------------------------
+-- 1.1.1.
+--------------------------------------------------------------------
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
-SHOW INSTANCE STATUS mysqld1;
-instance_name status version_number version
-mysqld1 online VERSION_NUMBER VERSION
-SHOW INSTANCE STATUS mysqld2;
-instance_name status version_number version
-mysqld2 offline VERSION_NUMBER VERSION
+
+--------------------------------------------------------------------
+-- 1.1.2.
+--------------------------------------------------------------------
START INSTANCE mysqld2;
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 online
-SHOW INSTANCE STATUS mysqld1;
-instance_name status version_number version
-mysqld1 online VERSION_NUMBER VERSION
-SHOW INSTANCE STATUS mysqld2;
-instance_name status version_number version
-mysqld2 online VERSION_NUMBER VERSION
SHOW VARIABLES LIKE 'port';
Variable_name Value
-port IM_MYSQLD1_PORT
+port IM_MYSQLD2_PORT
+
+--------------------------------------------------------------------
+-- 1.1.3.
+--------------------------------------------------------------------
STOP INSTANCE mysqld2;
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
SHOW INSTANCE STATUS mysqld1;
-instance_name status version_number version
-mysqld1 online VERSION_NUMBER VERSION
+instance_name state version_number version mysqld_compatible
+mysqld1 online VERSION_NUMBER VERSION no
SHOW INSTANCE STATUS mysqld2;
-instance_name status version_number version
-mysqld2 offline VERSION_NUMBER VERSION
+instance_name state version_number version mysqld_compatible
+mysqld2 offline VERSION_NUMBER VERSION no
+
+--------------------------------------------------------------------
+-- 1.1.4.
+--------------------------------------------------------------------
START INSTANCE mysqld3;
ERROR HY000: Bad instance name. Check that the instance with such a name exists
START INSTANCE mysqld1;
ERROR HY000: The instance is already started
+
+--------------------------------------------------------------------
+-- 1.1.5.
+--------------------------------------------------------------------
STOP INSTANCE mysqld3;
ERROR HY000: Bad instance name. Check that the instance with such a name exists
+
+--------------------------------------------------------------------
+-- 1.1.6.
+--------------------------------------------------------------------
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
Killing the process...
Sleeping...
Success: the process was restarted.
+
+--------------------------------------------------------------------
+-- 1.1.7.
+--------------------------------------------------------------------
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
START INSTANCE mysqld2;
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 online
Killing the process...
Sleeping...
Success: the process was killed.
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
+
+--------------------------------------------------------------------
+-- 1.1.8.
+--------------------------------------------------------------------
SHOW INSTANCE STATUS;
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+
+--------------------------------------------------------------------
+-- BUG#12813
+--------------------------------------------------------------------
START INSTANCE mysqld1,mysqld2,mysqld3;
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
STOP INSTANCE mysqld1,mysqld2,mysqld3;
diff --git a/mysql-test/r/im_options.result b/mysql-test/r/im_options.result
new file mode 100644
index 00000000000..8039333b7d9
--- /dev/null
+++ b/mysql-test/r/im_options.result
@@ -0,0 +1,150 @@
+--------------------------------------------------------------------
+server_id = 1
+server_id = 2
+--------------------------------------------------------------------
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SHOW INSTANCES;
+instance_name state
+mysqld1 starting
+mysqld2 offline
+UNSET mysqld1.server_id;
+ERROR HY000: The instance is active. Stop the instance first
+SET mysqld1.server_id = 11;
+ERROR HY000: The instance is active. Stop the instance first
+CREATE INSTANCE mysqld3 datadir = '/';
+START INSTANCE mysqld3;
+UNSET mysqld3.server_id;
+ERROR HY000: The instance is active. Stop the instance first
+SET mysqld3.server_id = 11;
+ERROR HY000: The instance is active. Stop the instance first
+STOP INSTANCE mysqld3;
+SHOW INSTANCE STATUS mysqld3;
+instance_name state version_number version mysqld_compatible
+mysqld3 offline VERSION_NUMBER VERSION no
+UNSET mysqld2.server_id;
+UNSET mysqld2.server_id;
+SHOW INSTANCE OPTIONS mysqld2;
+option_name value
+instance_name option_value
+socket option_value
+pid-file option_value
+port option_value
+datadir option_value
+log option_value
+log-error option_value
+log-slow-queries option_value
+language option_value
+character-sets-dir option_value
+basedir option_value
+skip-stack-trace option_value
+skip-innodb option_value
+skip-bdb option_value
+skip-ndbcluster option_value
+nonguarded option_value
+log-output option_value
+SET mysqld2.server_id = 2;
+SET mysqld2.server_id = 2;
+SHOW INSTANCE OPTIONS mysqld2;
+option_name value
+instance_name option_value
+socket option_value
+pid-file option_value
+port option_value
+datadir option_value
+log option_value
+log-error option_value
+log-slow-queries option_value
+language option_value
+character-sets-dir option_value
+basedir option_value
+skip-stack-trace option_value
+skip-innodb option_value
+skip-bdb option_value
+skip-ndbcluster option_value
+nonguarded option_value
+log-output option_value
+server_id option_value
+UNSET mysqld2.server_id = 11;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
+--------------------------------------------------------------------
+aaa
+--------------------------------------------------------------------
+bbb
+--------------------------------------------------------------------
+ccc=0010
+--------------------------------------------------------------------
+ddd=0020
+--------------------------------------------------------------------
+UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
+ERROR HY000: Bad instance name. Check that the instance with such a name exists
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
+ERROR HY000: The instance is active. Stop the instance first
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
+ERROR HY000: Bad instance name. Check that the instance with such a name exists
+--------------------------------------------------------------------
+server_id = 1
+server_id=2
+--------------------------------------------------------------------
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
+ERROR HY000: The instance is active. Stop the instance first
+--------------------------------------------------------------------
+server_id = 1
+server_id=2
+--------------------------------------------------------------------
+DROP INSTANCE mysqld3;
+SET mysqld2.server_id=222;
+SET mysqld2.server_id = 222;
+SET mysqld2.server_id = 222 ;
+SET mysqld2 . server_id = 222 ;
+SET mysqld2 . server_id = 222 , mysqld2 . aaa , mysqld2 . bbb ;
+--------------------------------------------------------------------
+server_id = 1
+server_id=222
+--------------------------------------------------------------------
+aaa
+--------------------------------------------------------------------
+bbb
+--------------------------------------------------------------------
+UNSET mysqld2 . aaa , mysqld2 . bbb ;
+--------------------------------------------------------------------
+server_id = 1
+server_id=222
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+server_id = 1
+server_id=222
+--------------------------------------------------------------------
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SHOW INSTANCES;
+instance_name state
+mysqld1 online
+mysqld2 offline
+FLUSH INSTANCES;
+ERROR HY000: At least one instance is active. Stop all instances first
+STOP INSTANCE mysqld1;
+SHOW INSTANCES;
+instance_name state
+mysqld1 offline
+mysqld2 offline
+FLUSH INSTANCES;
diff --git a/mysql-test/r/im_options_set.result b/mysql-test/r/im_options_set.result
deleted file mode 100644
index 5e6c740624e..00000000000
--- a/mysql-test/r/im_options_set.result
+++ /dev/null
@@ -1,20 +0,0 @@
-server_id = 1
-server_id = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
-SET mysqld1.server_id = 11;
-server_id =11
-server_id = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
-SET mysqld2.server_id = 12;
-server_id =11
-server_id =12
-FLUSH INSTANCES;
-server_id =11
-server_id =12
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
diff --git a/mysql-test/r/im_options_unset.result b/mysql-test/r/im_options_unset.result
deleted file mode 100644
index bf54025edb7..00000000000
--- a/mysql-test/r/im_options_unset.result
+++ /dev/null
@@ -1,15 +0,0 @@
-server_id = 1
-server_id = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
-UNSET mysqld1.server_id;
-server_id = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
-UNSET mysqld2.server_id;
-FLUSH INSTANCES;
-SHOW VARIABLES LIKE 'server_id';
-Variable_name Value
-server_id 1
diff --git a/mysql-test/r/im_utils.result b/mysql-test/r/im_utils.result
index 504b2efe4af..ae8e03bf8ea 100644
--- a/mysql-test/r/im_utils.result
+++ b/mysql-test/r/im_utils.result
@@ -1,11 +1,10 @@
SHOW INSTANCES;
-instance_name status
+instance_name state
mysqld1 online
mysqld2 offline
SHOW INSTANCE OPTIONS mysqld1;
option_name value
instance_name VALUE
-mysqld-path VALUE
socket VALUE
pid-file VALUE
port VALUE
@@ -25,8 +24,6 @@ log-output VALUE
SHOW INSTANCE OPTIONS mysqld2;
option_name value
instance_name VALUE
-mysqld-path VALUE
-nonguarded VALUE
socket VALUE
pid-file VALUE
port VALUE
@@ -42,6 +39,7 @@ skip-stack-trace VALUE
skip-innodb VALUE
skip-bdb VALUE
skip-ndbcluster VALUE
+nonguarded VALUE
log-output VALUE
START INSTANCE mysqld2;
STOP INSTANCE mysqld2;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 9aeaae6c6c1..603b7815d5b 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1162,3 +1162,16 @@ select user,db from information_schema.processlist;
user db
user3148 test
drop user user3148@localhost;
+grant select on test.* to mysqltest_1@localhost;
+create table t1 (id int);
+create view v1 as select * from t1;
+create definer = mysqltest_1@localhost
+sql security definer view v2 as select 1;
+select * from information_schema.views
+where table_name='v1' or table_name='v2';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE
+NULL test v1 NONE YES root@localhost DEFINER
+NULL test v2 select 1 AS `1` NONE NO mysqltest_1@localhost DEFINER
+drop view v1, v2;
+drop table t1;
+drop user mysqltest_1@localhost;
diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result
index 37537e257da..5919e0f071d 100644
--- a/mysql-test/r/information_schema_db.result
+++ b/mysql-test/r/information_schema_db.result
@@ -1,3 +1,7 @@
+drop table if exists t1,t2;
+drop view if exists v1,v2;
+drop function if exists f1;
+drop function if exists f2;
use INFORMATION_SCHEMA;
show tables;
Tables_in_information_schema
@@ -31,10 +35,12 @@ TABLE_CONSTRAINTS
TABLE_PRIVILEGES
TRIGGERS
create database `inf%`;
+create database mbase;
use `inf%`;
show tables;
Tables_in_inf%
grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost';
+grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost';
create table t1 (f1 int);
create function func1(curr_int int) returns int
begin
@@ -43,9 +49,58 @@ select max(f1) from t1 into ret_val;
return ret_val;
end|
create view v1 as select f1 from t1 where f1 = func1(f1);
+create function func2() returns int return 1;
+use mbase;
+create procedure p1 ()
+begin
+select table_name from information_schema.key_column_usage
+order by table_name;
+end|
+create table t1
+(f1 int(10) unsigned not null,
+f2 varchar(100) not null,
+primary key (f1), unique key (f2));
select * from information_schema.tables;
+call mbase.p1();
+call mbase.p1();
+call mbase.p1();
+use `inf%`;
drop user mysqltest_1@localhost;
+drop table t1;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='inf%' and func2();
+table_name table_type table_comment
+v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='inf%' and func2();
+table_name table_type table_comment
+v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define
drop view v1;
drop function func1;
-drop table t1;
+drop function func2;
drop database `inf%`;
+drop procedure mbase.p1;
+drop database mbase;
+use test;
+create table t1 (i int);
+create function f1 () returns int return (select max(i) from t1);
+create view v1 as select f1();
+create table t2 (id int);
+create function f2 () returns int return (select max(i) from t2);
+create view v2 as select f2();
+drop table t2;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='test';
+table_name table_type table_comment
+t1 BASE TABLE
+v1 VIEW VIEW
+v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
+drop table t1;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='test';
+table_name table_type table_comment
+v1 VIEW View 'test.v1' references invalid table(s) or column(s) or function(s) or define
+v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
+drop function f1;
+drop function f2;
+drop view v1, v2;
diff --git a/mysql-test/r/information_schema_part.result b/mysql-test/r/information_schema_part.result
index cf49abf888a..ef3ee19656b 100644
--- a/mysql-test/r/information_schema_part.result
+++ b/mysql-test/r/information_schema_part.result
@@ -111,3 +111,32 @@ NULL test t1 p0 NULL 1 NULL LINEAR HASH NULL month(f1) NULL NULL 0 0 0 # 1024 0
NULL test t1 p1 NULL 2 NULL LINEAR HASH NULL month(f1) NULL NULL 0 0 0 # 1024 0 # # NULL NULL default 0 default
NULL test t1 p2 NULL 3 NULL LINEAR HASH NULL month(f1) NULL NULL 0 0 0 # 1024 0 # # NULL NULL default 0 default
drop table t1;
+create table t1 (a int)
+PARTITION BY RANGE (a)
+SUBPARTITION BY LINEAR HASH (a)
+(PARTITION p0 VALUES LESS THAN (10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY LINEAR HASH (a) (PARTITION p0 VALUES LESS THAN (10) ENGINE = MyISAM)
+select SUBPARTITION_METHOD FROM information_schema.partitions WHERE
+table_schema="test" AND table_name="t1";
+SUBPARTITION_METHOD
+LINEAR HASH
+drop table t1;
+create table t1 (a int)
+PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN
+(10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY LIST (a) (PARTITION p0 VALUES IN (10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53) ENGINE = MyISAM)
+SELECT PARTITION_DESCRIPTION FROM information_schema.partitions WHERE
+table_schema = "test" AND table_name = "t1";
+PARTITION_DESCRIPTION
+10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53
+drop table t1;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 7ae87e42b8c..eca6d148567 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1822,7 +1822,7 @@ Variable_name Value
innodb_sync_spin_loops 20
show variables like "innodb_thread_concurrency";
Variable_name Value
-innodb_thread_concurrency 20
+innodb_thread_concurrency 8
set global innodb_thread_concurrency=1001;
show variables like "innodb_thread_concurrency";
Variable_name Value
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result
index fe0f78d5ac1..d79f957559c 100644
--- a/mysql-test/r/innodb_mysql.result
+++ b/mysql-test/r/innodb_mysql.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t1m,t1i,t2m,t2i,t4;
create table t1 (
c_id int(11) not null default '0',
org_id int(11) default null,
@@ -54,6 +54,278 @@ c.c_id = 218 and expiredate is null;
slai_id
12
drop table t1, t2;
+create table t1m (a int) engine=myisam;
+create table t1i (a int) engine=innodb;
+create table t2m (a int) engine=myisam;
+create table t2i (a int) engine=innodb;
+insert into t2m values (5);
+insert into t2i values (5);
+select min(a) from t1m;
+min(a)
+NULL
+select min(7) from t1m;
+min(7)
+NULL
+select min(7) from DUAL;
+min(7)
+NULL
+explain select min(7) from t2m join t1m;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
+select min(7) from t2m join t1m;
+min(7)
+NULL
+select max(a) from t1m;
+max(a)
+NULL
+select max(7) from t1m;
+max(7)
+NULL
+select max(7) from DUAL;
+max(7)
+NULL
+explain select max(7) from t2m join t1m;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
+select max(7) from t2m join t1m;
+max(7)
+NULL
+select 1, min(a) from t1m where a=99;
+1 min(a)
+1 NULL
+select 1, min(a) from t1m where 1=99;
+1 min(a)
+1 NULL
+select 1, min(1) from t1m where a=99;
+1 min(1)
+1 NULL
+select 1, min(1) from t1m where 1=99;
+1 min(1)
+1 NULL
+select 1, max(a) from t1m where a=99;
+1 max(a)
+1 NULL
+select 1, max(a) from t1m where 1=99;
+1 max(a)
+1 NULL
+select 1, max(1) from t1m where a=99;
+1 max(1)
+1 NULL
+select 1, max(1) from t1m where 1=99;
+1 max(1)
+1 NULL
+select min(a) from t1i;
+min(a)
+NULL
+select min(7) from t1i;
+min(7)
+NULL
+select min(7) from DUAL;
+min(7)
+NULL
+explain select min(7) from t2i join t1i;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2i ALL NULL NULL NULL NULL 1
+1 SIMPLE t1i ALL NULL NULL NULL NULL 1
+select min(7) from t2i join t1i;
+min(7)
+NULL
+select max(a) from t1i;
+max(a)
+NULL
+select max(7) from t1i;
+max(7)
+NULL
+select max(7) from DUAL;
+max(7)
+NULL
+explain select max(7) from t2i join t1i;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2i ALL NULL NULL NULL NULL 1
+1 SIMPLE t1i ALL NULL NULL NULL NULL 1
+select max(7) from t2i join t1i;
+max(7)
+NULL
+select 1, min(a) from t1i where a=99;
+1 min(a)
+1 NULL
+select 1, min(a) from t1i where 1=99;
+1 min(a)
+1 NULL
+select 1, min(1) from t1i where a=99;
+1 min(1)
+1 NULL
+select 1, min(1) from t1i where 1=99;
+1 min(1)
+1 NULL
+select 1, max(a) from t1i where a=99;
+1 max(a)
+1 NULL
+select 1, max(a) from t1i where 1=99;
+1 max(a)
+1 NULL
+select 1, max(1) from t1i where a=99;
+1 max(1)
+1 NULL
+select 1, max(1) from t1i where 1=99;
+1 max(1)
+1 NULL
+explain select count(*), min(7), max(7) from t1m, t1i;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t1i ALL NULL NULL NULL NULL 1
+select count(*), min(7), max(7) from t1m, t1i;
+count(*) min(7) max(7)
+0 NULL NULL
+explain select count(*), min(7), max(7) from t1m, t2i;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t2i ALL NULL NULL NULL NULL 1
+select count(*), min(7), max(7) from t1m, t2i;
+count(*) min(7) max(7)
+0 NULL NULL
+explain select count(*), min(7), max(7) from t2m, t1i;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2m system NULL NULL NULL NULL 1
+1 SIMPLE t1i ALL NULL NULL NULL NULL 1
+select count(*), min(7), max(7) from t2m, t1i;
+count(*) min(7) max(7)
+0 NULL NULL
+drop table t1m, t1i, t2m, t2i;
+create table t1 (
+a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+);
+insert into t1 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
+create table t4 (
+pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+) engine=innodb;
+insert into t4 (a1, a2, b, c, d, dummy) select * from t1;
+create index idx12672_0 on t4 (a1);
+create index idx12672_1 on t4 (a1,a2,b,c);
+create index idx12672_2 on t4 (a1,a2,b);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select distinct a1 from t4 where pk_col not in (1,2,3,4);
+a1
+a
+b
+c
+d
+drop table t1,t4;
+create table t1 (
+a varchar(30), b varchar(30), primary key(a), key(b)
+) engine=innodb;
+select distinct a from t1;
+a
+drop table t1;
+create table t1(a int, key(a)) engine=innodb;
+insert into t1 values(1);
+select a, count(a) from t1 group by a with rollup;
+a count(a)
+1 1
+NULL 1
+drop table t1;
+create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb;
+insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d");
+alter table t1 drop primary key, add primary key (f2, f1);
+explain select distinct f1 a, f1 b from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 5 NULL 4 Using index; Using temporary
+explain select distinct f1, f2 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL PRIMARY 5 NULL 3 Using index for group-by; Using temporary
+drop table t1;
+set storage_engine=innodb;
+CREATE TABLE t1 (a int, b int);
+insert into t1 values (1,1),(1,2);
+CREATE TABLE t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+drop table if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+drop table if exists t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TABLE t2 (a int, b int, primary key (a));
+BEGIN;
+INSERT INTO t2 values(100,100);
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+100 100
+ROLLBACK;
+SELECT * from t2;
+a b
+100 100
+TRUNCATE table t2;
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+drop table t2;
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a));
+BEGIN;
+INSERT INTO t2 values(100,100);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+100 100
+COMMIT;
+BEGIN;
+INSERT INTO t2 values(101,101);
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+100 100
+101 101
+ROLLBACK;
+SELECT * from t2;
+a b
+100 100
+TRUNCATE table t2;
+INSERT INTO t2 select * from t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SELECT * from t2;
+a b
+drop table t1,t2;
create table t1(f1 varchar(800) binary not null, key(f1)) engine = innodb
character set utf8 collate utf8_general_ci;
Warnings:
diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result
index 5e9ab480558..18bd6d7e796 100644
--- a/mysql-test/r/insert.result
+++ b/mysql-test/r/insert.result
@@ -2,8 +2,8 @@ drop table if exists t1,t2,t3;
create table t1 (a int not null);
insert into t1 values (1);
insert into t1 values (a+2);
-insert into t1 values (a+3);
-insert into t1 values (4),(a+5);
+insert into t1 values (a+3),(a+4);
+insert into t1 values (5),(a+6);
select * from t1;
a
1
@@ -11,6 +11,7 @@ a
3
4
5
+6
drop table t1;
create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username));
insert into t1 values (0,"mysql");
@@ -299,3 +300,24 @@ select count(*) from t2;
count(*)
25500
drop table t1,t2,t3;
+create table t1 (a int, b int);
+insert into t1 (a,b) values (a,b);
+insert into t1 SET a=1, b=a+1;
+insert into t1 (a,b) select 1,2;
+INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a);
+prepare stmt1 from ' replace into t1 (a,a) select 100, ''hundred'' ';
+execute stmt1;
+ERROR 42000: Column 'a' specified twice
+insert into t1 (a,b,b) values (1,1,1);
+ERROR 42000: Column 'b' specified twice
+insert into t1 (a,a) values (1,1,1);
+ERROR 21S01: Column count doesn't match value count at row 1
+insert into t1 (a,a) values (1,1);
+ERROR 42000: Column 'a' specified twice
+insert into t1 SET a=1,b=2,a=1;
+ERROR 42000: Column 'a' specified twice
+insert into t1 (b,b) select 1,2;
+ERROR 42000: Column 'b' specified twice
+INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a);
+ERROR 42000: Column 'b' specified twice
+drop table t1;
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index dc619aac4c1..b199ec5b2fb 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -1157,3 +1157,38 @@ a b
3 3
DROP VIEW v1,v2;
DROP TABLE t1,t2;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (b int);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (2), (3);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1);
+a b
+1 NULL
+2 2
+3 3
+4 NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1 OR 1);
+a b
+1 NULL
+2 2
+3 3
+4 NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (0 OR 1);
+a b
+1 NULL
+2 2
+3 3
+4 NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 2=2);
+a b
+1 NULL
+2 2
+3 3
+4 NULL
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 1=0);
+a b
+1 NULL
+2 2
+3 3
+4 NULL
+DROP TABLE t1,t2;
diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result
index 99f5277f817..406a92b9a08 100644
--- a/mysql-test/r/key_cache.result
+++ b/mysql-test/r/key_cache.result
@@ -191,10 +191,10 @@ cache index t1 in unknown_key_cache;
ERROR HY000: Unknown key cache 'unknown_key_cache'
cache index t1 key (unknown_key) in keycache1;
Table Op Msg_type Msg_text
-test.t1 assign_to_keycache error Key column 'unknown_key' doesn't exist in table
+test.t1 assign_to_keycache error Key 'unknown_key' doesn't exist in table 't1'
test.t1 assign_to_keycache status Operation failed
Warnings:
-Error 1072 Key column 'unknown_key' doesn't exist in table
+Error 1176 Key 'unknown_key' doesn't exist in table 't1'
select @@keycache2.key_buffer_size;
@@keycache2.key_buffer_size
4194304
diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result
index 0b314defece..72beee4b2e3 100644
--- a/mysql-test/r/loaddata.result
+++ b/mysql-test/r/loaddata.result
@@ -115,6 +115,15 @@ select @a, @b;
@a @b
NULL 15
truncate table t1;
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t1 set c=b;
+Warnings:
+Warning 1261 Row 1 doesn't contain data for all columns
+Warning 1261 Row 2 doesn't contain data for all columns
+select * from t1;
+a b c
+NULL 10 10
+NULL 15 15
+truncate table t1;
load data infile '../std_data_ln/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c="Wow";
select * from t1;
a b c
diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result
index 1ab51e9fad5..6d31d01d154 100644
--- a/mysql-test/r/lock_multi.result
+++ b/mysql-test/r/lock_multi.result
@@ -50,3 +50,27 @@ Field Type Null Key Default Extra
a int(11) YES NULL
unlock tables;
drop table t1;
+CREATE DATABASE mysqltest_1;
+FLUSH TABLES WITH READ LOCK;
+ DROP DATABASE mysqltest_1;
+DROP DATABASE mysqltest_1;
+ERROR HY000: Can't execute the query because you have a conflicting read lock
+UNLOCK TABLES;
+DROP DATABASE mysqltest_1;
+ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist
+use mysql;
+LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE;
+FLUSH TABLES;
+use mysql;
+ SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1;
+OPTIMIZE TABLES columns_priv, db, host, user;
+Table Op Msg_type Msg_text
+mysql.columns_priv optimize status OK
+mysql.db optimize status OK
+mysql.host optimize status OK
+mysql.user optimize status OK
+UNLOCK TABLES;
+Select_priv
+N
+use test;
+use test;
diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result
index 2164c18823f..c61dd2247ee 100644
--- a/mysql-test/r/log_tables.result
+++ b/mysql-test/r/log_tables.result
@@ -2,14 +2,14 @@ use mysql;
truncate table general_log;
select * from general_log;
event_time user_host thread_id server_id command_type argument
-TIMESTAMP root[root] @ localhost [] 1 1 Query select * from general_log
+TIMESTAMP USER_HOST THREAD_ID 1 Query select * from general_log
truncate table slow_log;
select * from slow_log;
start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text
truncate table general_log;
select * from general_log where argument like '%general_log%';
event_time user_host thread_id server_id command_type argument
-TIMESTAMP root[root] @ localhost [] 1 1 Query select * from general_log where argument like '%general_log%'
+TIMESTAMP USER_HOST THREAD_ID 1 Query select * from general_log where argument like '%general_log%'
create table join_test (verbose_comment varchar (80), command_type varchar(64));
insert into join_test values ("User performed a usual SQL query", "Query");
insert into join_test values ("New DB connection was registered", "Connect");
@@ -18,12 +18,12 @@ select verbose_comment, user_host, argument
from mysql.general_log join join_test
on (mysql.general_log.command_type = join_test.command_type);
verbose_comment user_host argument
-User performed a usual SQL query root[root] @ localhost [] select * from general_log where argument like '%general_log%'
-User performed a usual SQL query root[root] @ localhost [] create table join_test (verbose_comment varchar (80), command_type varchar(64))
-User performed a usual SQL query root[root] @ localhost [] insert into join_test values ("User performed a usual SQL query", "Query")
-User performed a usual SQL query root[root] @ localhost [] insert into join_test values ("New DB connection was registered", "Connect")
-User performed a usual SQL query root[root] @ localhost [] insert into join_test values ("Get the table info", "Field List")
-User performed a usual SQL query root[root] @ localhost [] select verbose_comment, user_host, argument
+User performed a usual SQL query USER_HOST select * from general_log where argument like '%general_log%'
+User performed a usual SQL query USER_HOST create table join_test (verbose_comment varchar (80), command_type varchar(64))
+User performed a usual SQL query USER_HOST insert into join_test values ("User performed a usual SQL query", "Query")
+User performed a usual SQL query USER_HOST insert into join_test values ("New DB connection was registered", "Connect")
+User performed a usual SQL query USER_HOST insert into join_test values ("Get the table info", "Field List")
+User performed a usual SQL query USER_HOST select verbose_comment, user_host, argument
from mysql.general_log join join_test
on (mysql.general_log.command_type = join_test.command_type)
drop table join_test;
@@ -59,10 +59,10 @@ create table bug16905 (s char(15) character set utf8 default 'пуÑто');
insert into bug16905 values ('новое');
select * from mysql.general_log;
event_time user_host thread_id server_id command_type argument
-TIMESTAMP root[root] @ localhost [] 2 1 Query set names utf8
-TIMESTAMP root[root] @ localhost [] 2 1 Query create table bug16905 (s char(15) character set utf8 default 'пуÑто')
-TIMESTAMP root[root] @ localhost [] 2 1 Query insert into bug16905 values ('новое')
-TIMESTAMP root[root] @ localhost [] 2 1 Query select * from mysql.general_log
+TIMESTAMP USER_HOST THREAD_ID 1 Query set names utf8
+TIMESTAMP USER_HOST THREAD_ID 1 Query create table bug16905 (s char(15) character set utf8 default 'пуÑто')
+TIMESTAMP USER_HOST THREAD_ID 1 Query insert into bug16905 values ('новое')
+TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.general_log
drop table bug16905;
truncate table mysql.slow_log;
set session long_query_time=1;
@@ -71,4 +71,4 @@ sleep(2)
0
select * from mysql.slow_log;
start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text
-TIMESTAMP, root[root] @ localhost [] USER_HOST, QUERY_TIME 1 0 test 0 0 1 select sleep(2)
+TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 test 0 0 1 select sleep(2)
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index ea02a703c65..6fdd105fd6c 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -519,3 +519,83 @@ a
30
drop view v1;
drop table t1, t2;
+create table t1 (i1 int, i2 int, i3 int);
+create table t2 (id int, c1 varchar(20), c2 varchar(20));
+insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from t1 order by i1;
+i1 i2 i3
+1 5 10
+2 2 2
+3 7 12
+4 5 2
+9 10 15
+select * from t2;
+id c1 c2
+9 abc def
+5 opq lmn
+2 test t t test
+update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from t1 order by i1;
+i1 i2 i3
+1 5 10
+2 15 2
+3 7 12
+4 5 2
+9 15 15
+select * from t2 order by id;
+id c1 c2
+2 test t ppc
+5 opq lmn
+9 abc ppc
+delete t1.*,t2.* from t1,t2 where t1.i2=t2.id;
+select * from t1 order by i1;
+i1 i2 i3
+2 15 2
+3 7 12
+9 15 15
+select * from t2 order by id;
+id c1 c2
+2 test t ppc
+9 abc ppc
+drop table t1, t2;
+create table t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1));
+create table t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id));
+insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from t1 order by i1;
+i1 i2 i3
+1 5 10
+2 2 2
+3 7 12
+4 5 2
+9 10 15
+select * from t2 order by id;
+id c1 c2
+2 test t t test
+5 opq lmn
+9 abc def
+update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from t1 order by i1;
+i1 i2 i3
+1 5 10
+2 15 2
+3 7 12
+4 5 2
+9 15 15
+select * from t2 order by id;
+id c1 c2
+2 test t ppc
+5 opq lmn
+9 abc ppc
+delete t1.*,t2.* from t1,t2 where t1.i2=t2.id;
+select * from t1 order by i1;
+i1 i2 i3
+2 15 2
+3 7 12
+9 15 15
+select * from t2 order by id;
+id c1 c2
+2 test t ppc
+9 abc ppc
+drop table t1, t2;
diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result
index 50e4cc28d93..c3be791b523 100644
--- a/mysql-test/r/mysqlbinlog.result
+++ b/mysql-test/r/mysqlbinlog.result
@@ -189,4 +189,9 @@ HEX(f)
select HEX(f) from t4;
HEX(f)
835C
-drop table t1, t2, t03, t04, t3, t4;
+flush logs;
+select * from t5 /* must be (1),(1) */;
+a
+1
+1
+drop table t1, t2, t03, t04, t3, t4, t5;
diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result
index acdbd868361..a3c14b13bde 100644
--- a/mysql-test/r/mysqlcheck.result
+++ b/mysql-test/r/mysqlcheck.result
@@ -1,3 +1,4 @@
+drop database if exists client_test_db;
DROP SCHEMA test;
CREATE SCHEMA test;
cluster.binlog_index OK
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 493e79d4136..7075e7dec6d 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
+DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa, t3;
drop database if exists mysqldump_test_db;
drop database if exists db1;
drop database if exists db2;
@@ -1509,6 +1509,7 @@ a b
12 meg
drop table t1, t2;
drop database db1;
+--fields-optionally-enclosed-by="
CREATE DATABASE mysqldump_test_db;
USE mysqldump_test_db;
CREATE TABLE t1 ( a INT );
@@ -1738,6 +1739,43 @@ t1 CREATE TABLE `t1` (
KEY `t1_name` (`t1_name`)
) ENGINE=MyISAM AUTO_INCREMENT=1003 DEFAULT CHARSET=latin1
drop table `t1`;
+create table t1(a int);
+create table t2(a int);
+create table t3(a int);
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+DROP TABLE IF EXISTS `t3`;
+CREATE TABLE `t3` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `t2`;
+CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+drop table t1, t2, t3;
End of 4.1 tests
create table t1 (a binary(1), b blob);
insert into t1 values ('','');
diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result
index 7c687ff33a1..e506973f347 100644
--- a/mysql-test/r/ndb_alter_table.result
+++ b/mysql-test/r/ndb_alter_table.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
drop database if exists mysqltest;
CREATE TABLE t1 (
a INT NOT NULL,
@@ -328,3 +328,24 @@ select 'no_copy' from ndb_show_tables where id = @t1_id and name like '%t1%';
no_copy
no_copy
DROP TABLE t1, ndb_show_tables;
+create table t1 (a int primary key auto_increment, b int) engine=ndb;
+insert into t1 (b) values (101),(102),(103);
+select * from t1 where a = 3;
+a b
+3 103
+alter table t1 rename t2;
+insert into t2 (b) values (201),(202),(203);
+select * from t2 where a = 6;
+a b
+6 203
+alter table t2 add c int;
+insert into t2 (b) values (301),(302),(303);
+select * from t2 where a = 9;
+a b c
+9 303 NULL
+alter table t2 rename t1;
+insert into t1 (b) values (401),(402),(403);
+select * from t1 where a = 12;
+a b c
+12 403 NULL
+drop table t1;
diff --git a/mysql-test/r/ndb_autodiscover3.result b/mysql-test/r/ndb_autodiscover3.result
index 6e3e5fcc335..86495ebb3eb 100644
--- a/mysql-test/r/ndb_autodiscover3.result
+++ b/mysql-test/r/ndb_autodiscover3.result
@@ -18,6 +18,7 @@ select * from t2;
ERROR 42S02: Table 'test.t2' doesn't exist
show tables like 't2';
Tables_in_test (t2)
+reset master;
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from t2 order by a limit 3;
@@ -30,10 +31,12 @@ a
1
2
3
+reset master;
select * from t2;
ERROR 42S02: Table 'test.t2' doesn't exist
show tables like 't2';
Tables_in_test (t2)
+reset master;
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from t2 order by a limit 3;
@@ -46,4 +49,5 @@ a
1
2
3
+reset master;
drop table t2;
diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result
index 4a1f5f587df..631165d9fc8 100644
--- a/mysql-test/r/ndb_basic.result
+++ b/mysql-test/r/ndb_basic.result
@@ -642,30 +642,30 @@ counter datavalue
6 newval
7 newval
8 newval
-35 newval
-36 newval
-37 newval
-38 newval
-39 newval
-40 newval
-41 newval
-42 newval
-43 newval
-44 newval
-45 newval
-46 newval
-47 newval
-48 newval
-49 newval
-50 newval
-51 newval
-52 newval
-53 newval
-54 newval
-55 newval
-56 newval
-57 newval
-58 newval
+9 newval
+10 newval
+11 newval
+12 newval
+13 newval
+14 newval
+15 newval
+16 newval
+17 newval
+18 newval
+19 newval
+20 newval
+21 newval
+22 newval
+23 newval
+24 newval
+25 newval
+26 newval
+27 newval
+28 newval
+29 newval
+30 newval
+31 newval
+32 newval
drop table t1;
CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb;
select * from t1;
@@ -748,3 +748,11 @@ f1 f2 f3
111111 aaaaaa 1
222222 bbbbbb 2
drop table t1;
+CREATE TABLE t1 (a VARCHAR(255) NOT NULL,
+CONSTRAINT pk_a PRIMARY KEY (a))engine=ndb;
+CREATE TABLE t2(a VARCHAR(255) NOT NULL,
+b VARCHAR(255) NOT NULL,
+c VARCHAR(255) NOT NULL,
+CONSTRAINT pk_b_c_id PRIMARY KEY (b,c),
+CONSTRAINT fk_a FOREIGN KEY(a) REFERENCES t1(a))engine=ndb;
+drop table t1, t2;
diff --git a/mysql-test/r/ndb_blob.result b/mysql-test/r/ndb_blob.result
index 7a781ae3bde..829c67905bf 100644
--- a/mysql-test/r/ndb_blob.result
+++ b/mysql-test/r/ndb_blob.result
@@ -500,3 +500,69 @@ select count(*) from t1;
count(*)
0
drop table t1;
+create table t1 (
+a varchar(40) not null,
+b mediumint not null,
+t text,
+c varchar(2) not null,
+d bigint not null,
+primary key (a,b,c),
+key (c,a),
+unique key (d)
+) engine=ndb;
+insert into t1 (a,b,c,d,t) values ('a',1110,'a',1,@v1);
+insert into t1 (a,b,c,d,t) values ('b',1110,'a',2,@v2);
+insert into t1 (a,b,c,d,t) values ('a',1110,'b',3,@v3);
+insert into t1 (a,b,c,d,t) values ('b',1110,'b',4,@v4);
+select a,b,c,d,sha1(t) from t1 order by c,a;
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+b 1110 a 2 b238654911689bfb626a3ef9dba4a1ca074e6a5e
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+b 1110 b 4 NULL
+select a,b,c,d,sha1(t) from t1 where a='a' and b=1110 and c='a';
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+select a,b,c,d,sha1(t) from t1 where a='a' and b=1110 and c='b';
+a b c d sha1(t)
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+update t1 set t=@v4 where a='b' and b=1110 and c='a';
+update t1 set t=@v2 where a='b' and b=1110 and c='b';
+select a,b,c,d,sha1(t) from t1 order by c,a;
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+b 1110 a 2 NULL
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+b 1110 b 4 b238654911689bfb626a3ef9dba4a1ca074e6a5e
+update t1 set t=@v2 where d=2;
+update t1 set t=@v4 where d=4;
+select a,b,c,d,sha1(t) from t1 order by c,a;
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+b 1110 a 2 b238654911689bfb626a3ef9dba4a1ca074e6a5e
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+b 1110 b 4 NULL
+update t1 set t=@v4 where a='b' and c='a';
+update t1 set t=@v2 where a='b' and c='b';
+select a,b,c,d,sha1(t) from t1 order by c,a;
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+b 1110 a 2 NULL
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+b 1110 b 4 b238654911689bfb626a3ef9dba4a1ca074e6a5e
+update t1 set t=@v2 where b+d=1112;
+update t1 set t=@v4 where b+d=1114;
+select a,b,c,d,sha1(t) from t1 order by c,a;
+a b c d sha1(t)
+a 1110 a 1 558a30713786aa72f66abc1e6a521d55aacdeeb5
+b 1110 a 2 b238654911689bfb626a3ef9dba4a1ca074e6a5e
+a 1110 b 3 2b6515f29c20b8e9e17cc597527e516c0de8d612
+b 1110 b 4 NULL
+delete from t1 where a='a' and b=1110 and c='a';
+delete from t1 where a='b' and c='a';
+delete from t1 where d=3;
+delete from t1 where b+d=1114;
+select count(*) from t1;
+count(*)
+0
+drop table t1;
diff --git a/mysql-test/r/ndb_dd_backuprestore.result b/mysql-test/r/ndb_dd_backuprestore.result
index e7568e4ce49..33edf6783e6 100644
--- a/mysql-test/r/ndb_dd_backuprestore.result
+++ b/mysql-test/r/ndb_dd_backuprestore.result
@@ -155,333 +155,10 @@ DROP TABLE test.t1;
DROP TABLE test.t2;
DROP TABLE test.t3;
DROP TABLE test.t4;
-**** Test 3 Adding partition Test backup and restore ****
-CREATE TABLESPACE table_space2
-ADD DATAFILE './table_space2/datafile.dat'
-USE LOGFILE GROUP log_group1
-INITIAL_SIZE 12M
-ENGINE NDB;
-CREATE TABLE test.t1 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(150) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space1 STORAGE DISK ENGINE=NDB PARTITION BY HASH(c3) PARTITIONS 4;
-CREATE TABLE test.t4 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(180) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY HASH(c3) PARTITIONS 2;
-CREATE TABLE test.t2 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space2 STORAGE DISK ENGINE=NDB PARTITION BY KEY(c3) (PARTITION p0 ENGINE = NDB, PARTITION p1 ENGINE = NDB);
-CREATE TABLE test.t5 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY KEY(pk1) (PARTITION p0 ENGINE = NDB, PARTITION p1 ENGINE = NDB);
-CREATE TABLE test.t3 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(202) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space2 STORAGE DISK ENGINE=NDB PARTITION BY RANGE (c3) PARTITIONS 3 (PARTITION x1 VALUES LESS THAN (105), PARTITION x2 VALUES LESS THAN (333), PARTITION x3 VALUES LESS THAN (720));
-CREATE TABLE test.t6 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(220) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY RANGE (pk1) PARTITIONS 2 (PARTITION x1 VALUES LESS THAN (333), PARTITION x2 VALUES LESS THAN (720));
-SHOW CREATE TABLE test.t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(150) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH (c3) PARTITIONS 4
-SHOW CREATE TABLE test.t2;
-Table Create Table
-t2 CREATE TABLE `t2` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` text NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space2 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY (c3) (PARTITION p0 ENGINE = ndbcluster, PARTITION p1 ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t3;
-Table Create Table
-t3 CREATE TABLE `t3` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(202) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space2 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (c3) (PARTITION x1 VALUES LESS THAN (105) ENGINE = ndbcluster, PARTITION x2 VALUES LESS THAN (333) ENGINE = ndbcluster, PARTITION x3 VALUES LESS THAN (720) ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t4;
-Table Create Table
-t4 CREATE TABLE `t4` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(180) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH (c3) PARTITIONS 2
-SHOW CREATE TABLE test.t5;
-Table Create Table
-t5 CREATE TABLE `t5` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` text NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY (pk1) (PARTITION p0 ENGINE = ndbcluster, PARTITION p1 ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t6;
-Table Create Table
-t6 CREATE TABLE `t6` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(220) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (pk1) (PARTITION x1 VALUES LESS THAN (333) ENGINE = ndbcluster, PARTITION x2 VALUES LESS THAN (720) ENGINE = ndbcluster)
-SELECT * FROM information_schema.partitions WHERE table_name= 't1';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t1 p0 NULL 1 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p1 NULL 2 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p2 NULL 3 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p3 NULL 4 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't2';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t2 p0 NULL 1 NULL KEY NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t2 p1 NULL 2 NULL KEY NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't3';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t3 x1 NULL 1 NULL RANGE NULL c3 NULL 105 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t3 x2 NULL 2 NULL RANGE NULL c3 NULL 333 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t3 x3 NULL 3 NULL RANGE NULL c3 NULL 720 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't4';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t4 p0 NULL 1 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t4 p1 NULL 2 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't5';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t5 p0 NULL 1 NULL KEY NULL pk1 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t5 p1 NULL 2 NULL KEY NULL pk1 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't6';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t6 x1 NULL 1 NULL RANGE NULL pk1 NULL 333 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t6 x2 NULL 2 NULL RANGE NULL pk1 NULL 720 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT COUNT(*) FROM test.t1;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t1 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas 2 0
-249 Sweden, Texas 4 0
-248 Sweden, Texas 6 0
-247 Sweden, Texas 8 0
-246 Sweden, Texas 10 0
-SELECT COUNT(*) FROM test.t2;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t2 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 1 1
-249 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 3 1
-248 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 5 1
-247 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 7 1
-246 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 9 1
-SELECT COUNT(*) FROM test.t3;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t3 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 0 1
-249 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 2 1
-248 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 4 1
-247 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 6 1
-246 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 8 1
-SELECT COUNT(*) FROM test.t4;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t4 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas 2 0
-249 Sweden, Texas 4 0
-248 Sweden, Texas 6 0
-247 Sweden, Texas 8 0
-246 Sweden, Texas 10 0
-SELECT COUNT(*) FROM test.t5;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t5 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 1 1
-249 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 3 1
-248 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 5 1
-247 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 7 1
-246 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 9 1
-SELECT COUNT(*) FROM test.t6;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t6 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 0 1
-249 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 2 1
-248 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 4 1
-247 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 6 1
-246 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 8 1
-CREATE TEMPORARY TABLE IF NOT EXISTS test.backup_info (id INT, backup_id INT) ENGINE = HEAP;
-DELETE FROM test.backup_info;
-LOAD DATA INFILE '../tmp.dat' INTO TABLE test.backup_info FIELDS TERMINATED BY ',';
-SELECT @the_backup_id:=backup_id FROM test.backup_info;
-@the_backup_id:=backup_id
-<the_backup_id>
-DROP TABLE test.backup_info;
-DROP TABLE test.t1;
-DROP TABLE test.t2;
-DROP TABLE test.t3;
-DROP TABLE test.t4;
-DROP TABLE test.t5;
-DROP TABLE test.t6;
ALTER TABLESPACE table_space1
DROP DATAFILE './table_space1/datafile.dat'
ENGINE = NDB;
-ALTER TABLESPACE table_space2
-DROP DATAFILE './table_space2/datafile.dat'
-ENGINE = NDB;
DROP TABLESPACE table_space1
ENGINE = NDB;
-DROP TABLESPACE table_space2
-ENGINE = NDB;
DROP LOGFILE GROUP log_group1
ENGINE =NDB;
-SHOW CREATE TABLE test.t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(150) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH (c3) PARTITIONS 4
-SHOW CREATE TABLE test.t2;
-Table Create Table
-t2 CREATE TABLE `t2` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` text NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space2 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY (c3) (PARTITION p0 ENGINE = ndbcluster, PARTITION p1 ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t3;
-Table Create Table
-t3 CREATE TABLE `t3` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(202) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) TABLESPACE table_space2 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (c3) (PARTITION x1 VALUES LESS THAN (105) ENGINE = ndbcluster, PARTITION x2 VALUES LESS THAN (333) ENGINE = ndbcluster, PARTITION x3 VALUES LESS THAN (720) ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t4;
-Table Create Table
-t4 CREATE TABLE `t4` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(180) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH (c3) PARTITIONS 2
-SHOW CREATE TABLE test.t5;
-Table Create Table
-t5 CREATE TABLE `t5` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` text NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY (pk1) (PARTITION p0 ENGINE = ndbcluster, PARTITION p1 ENGINE = ndbcluster)
-SHOW CREATE TABLE test.t6;
-Table Create Table
-t6 CREATE TABLE `t6` (
- `pk1` mediumint(9) NOT NULL AUTO_INCREMENT,
- `c2` varchar(220) NOT NULL,
- `c3` int(11) NOT NULL,
- `c4` bit(1) NOT NULL,
- PRIMARY KEY (`pk1`,`c3`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (pk1) (PARTITION x1 VALUES LESS THAN (333) ENGINE = ndbcluster, PARTITION x2 VALUES LESS THAN (720) ENGINE = ndbcluster)
-SELECT * FROM information_schema.partitions WHERE table_name= 't1';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t1 p0 NULL 1 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p1 NULL 2 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p2 NULL 3 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t1 p3 NULL 4 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't2';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t2 p0 NULL 1 NULL KEY NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t2 p1 NULL 2 NULL KEY NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't3';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t3 x1 NULL 1 NULL RANGE NULL c3 NULL 105 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t3 x2 NULL 2 NULL RANGE NULL c3 NULL 333 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t3 x3 NULL 3 NULL RANGE NULL c3 NULL 720 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't4';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t4 p0 NULL 1 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t4 p1 NULL 2 NULL HASH NULL c3 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't5';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t5 p0 NULL 1 NULL KEY NULL pk1 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t5 p1 NULL 2 NULL KEY NULL pk1 NULL NULL 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT * FROM information_schema.partitions WHERE table_name= 't6';
-TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
-NULL test t6 x1 NULL 1 NULL RANGE NULL pk1 NULL 333 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-NULL test t6 x2 NULL 2 NULL RANGE NULL pk1 NULL 720 0 0 0 NULL 0 0 NULL NULL NULL NULL default 0 default
-SELECT COUNT(*) FROM test.t1;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t1 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas 2 0
-249 Sweden, Texas 4 0
-248 Sweden, Texas 6 0
-247 Sweden, Texas 8 0
-246 Sweden, Texas 10 0
-SELECT COUNT(*) FROM test.t2;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t2 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 1 1
-249 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 3 1
-248 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 5 1
-247 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 7 1
-246 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 9 1
-SELECT COUNT(*) FROM test.t3;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t3 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 0 1
-249 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 2 1
-248 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 4 1
-247 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 6 1
-246 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 8 1
-SELECT COUNT(*) FROM test.t4;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t4 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas 2 0
-249 Sweden, Texas 4 0
-248 Sweden, Texas 6 0
-247 Sweden, Texas 8 0
-246 Sweden, Texas 10 0
-SELECT COUNT(*) FROM test.t5;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t5 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 1 1
-249 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 3 1
-248 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 5 1
-247 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 7 1
-246 Sweden, Texas, ITALY, Kyle, JO, JBM,TU 9 1
-SELECT COUNT(*) FROM test.t6;
-COUNT(*)
-250
-SELECT pk1, c2, c3, hex(c4) FROM test.t6 ORDER BY c3 LIMIT 5;
-pk1 c2 c3 hex(c4)
-250 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 0 1
-249 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 2 1
-248 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 4 1
-247 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 6 1
-246 TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU 8 1
-DROP TABLE test.t1;
-DROP TABLE test.t2;
-DROP TABLE test.t3;
-DROP TABLE test.t4;
-DROP TABLE test.t5;
-DROP TABLE test.t6;
-ALTER TABLESPACE table_space1 DROP DATAFILE './table_space1/datafile.dat' ENGINE=NDB;
-ALTER TABLESPACE table_space2 DROP DATAFILE './table_space2/datafile.dat' ENGINE=NDB;
-DROP TABLESPACE table_space1 ENGINE = NDB;
-DROP TABLESPACE table_space2 ENGINE = NDB;
-DROP LOGFILE GROUP log_group1 ENGINE = NDB;
diff --git a/mysql-test/r/ndb_dd_basic.result b/mysql-test/r/ndb_dd_basic.result
index 008be3aa79f..6c10fbe63b3 100644
--- a/mysql-test/r/ndb_dd_basic.result
+++ b/mysql-test/r/ndb_dd_basic.result
@@ -11,7 +11,7 @@ ADD UNDOFILE 'undofile02.dat'
INITIAL_SIZE = 4M
ENGINE=XYZ;
Warnings:
-Error 1266 Using storage engine MyISAM for table 'lg1'
+Error 1286 Unknown table engine 'XYZ'
Error 1465 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP'
CREATE TABLESPACE ts1
ADD DATAFILE 'datafile.dat'
diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result
index bd42595f060..88c6e00e215 100644
--- a/mysql-test/r/ndb_index_unique.result
+++ b/mysql-test/r/ndb_index_unique.result
@@ -144,7 +144,7 @@ b int unsigned not null,
c int unsigned,
UNIQUE (b, c) USING HASH
) engine=ndbcluster;
-ERROR 42000: Column 'c' is used with UNIQUE or INDEX but is not defined as NOT NULL
+ERROR 42000: Table handler doesn't support NULL in given index. Please change column 'c' to be NOT NULL or use another handler
CREATE TABLE t3 (
a int unsigned NOT NULL,
b int unsigned not null,
diff --git a/mysql-test/r/ndb_rename.result b/mysql-test/r/ndb_rename.result
new file mode 100644
index 00000000000..2cc2dfb3ff1
--- /dev/null
+++ b/mysql-test/r/ndb_rename.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS t1,t2;
+drop database if exists mysqltest;
+CREATE TABLE t1 (
+pk1 INT NOT NULL PRIMARY KEY,
+attr1 INT NOT NULL,
+attr2 INT,
+attr3 VARCHAR(10),
+INDEX i1(attr1)
+) ENGINE=ndbcluster;
+INSERT INTO t1 VALUES (0,0,0,"zero"),(1,1,1,"one"),(2,2,2,"two");
+SELECT * FROM t1 WHERE attr1 = 1;
+pk1 attr1 attr2 attr3
+1 1 1 one
+alter table t1 rename t2;
+SELECT * FROM t2 WHERE attr1 = 1;
+pk1 attr1 attr2 attr3
+1 1 1 one
+create database ndbtest;
+alter table t2 rename ndbtest.t2;
+SELECT * FROM ndbtest.t2 WHERE attr1 = 1;
+pk1 attr1 attr2 attr3
+1 1 1 one
+drop table ndbtest.t2;
+drop database ndbtest;
diff --git a/mysql-test/r/ndb_replace.result b/mysql-test/r/ndb_replace.result
index 5e49968ca64..cdcd935bfcc 100644
--- a/mysql-test/r/ndb_replace.result
+++ b/mysql-test/r/ndb_replace.result
@@ -30,4 +30,4 @@ REPLACE INTO t1 (i,j) VALUES (17,2);
SELECT * from t1 ORDER BY i;
i j k
3 1 42
-17 2 24
+17 2 NULL
diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result
index e471b5a3afa..7cbe91b3753 100644
--- a/mysql-test/r/not_embedded_server.result
+++ b/mysql-test/r/not_embedded_server.result
@@ -1,5 +1,6 @@
prepare stmt1 from ' show full processlist ';
execute stmt1;
Id User Host db Command Time State Info
+number event_scheduler localhost NULL Connect time Suspended NULL
number root localhost test Query time NULL show full processlist
deallocate prepare stmt1;
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result
index 614601a4394..2d11f739717 100644
--- a/mysql-test/r/partition.result
+++ b/mysql-test/r/partition.result
@@ -3,6 +3,23 @@ create table t1 (a int)
partition by key(a)
(partition p0 engine = MEMORY);
drop table t1;
+create table t1 (a int)
+partition by range (a)
+subpartition by key (a)
+(partition p0 values less than (1));
+alter table t1 add partition (partition p1 values less than (2));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY KEY (a) (PARTITION p0 VALUES LESS THAN (1) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (2) ENGINE = MyISAM)
+alter table t1 reorganize partition p1 into (partition p1 values less than (3));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY KEY (a) (PARTITION p0 VALUES LESS THAN (1) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (3) ENGINE = MyISAM)
+drop table t1;
CREATE TABLE t1 (
a int not null,
b int not null,
@@ -574,7 +591,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) (PARTITION p0 VALUES LESS THAN (100) )
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) (PARTITION p0 VALUES LESS THAN (100) ENGINE = MyISAM)
alter table t1 add partition (partition p1 values less than (200)
(subpartition subpart21));
show create table t1;
@@ -891,6 +908,10 @@ partition by key(a);
insert into t1 values (1);
create index inx1 on t1(a);
drop table t1;
+create table t1 (a int)
+partition by key (a)
+(partition p0 engine = MERGE);
+ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables
create table t1 (a varchar(1))
partition by key (a)
as select 'a';
@@ -918,4 +939,26 @@ CREATE TABLE t1 (a int, index(a)) PARTITION BY KEY(a);
ALTER TABLE t1 DISABLE KEYS;
ALTER TABLE t1 ENABLE KEYS;
DROP TABLE t1;
+create table t1 (a int)
+engine=MEMORY
+partition by key (a);
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair note The storage engine for the table doesn't support repair
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize note The storage engine for the table doesn't support optimize
+drop table t1;
+create database db99;
+use db99;
+create table t1 (a int not null)
+engine=archive
+partition by list (a)
+(partition p0 values in (1), partition p1 values in (2));
+insert into t1 values (1), (2);
+create index inx on t1 (a);
+alter table t1 add partition (partition p2 values in (3));
+alter table t1 drop partition p2;
+use test;
+drop database db99;
End of 5.1 tests
diff --git a/mysql-test/r/partition_02myisam.result b/mysql-test/r/partition_02myisam.result
index a7786bfcfbd..147e705f861 100644
--- a/mysql-test/r/partition_02myisam.result
+++ b/mysql-test/r/partition_02myisam.result
@@ -996,7 +996,7 @@ Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) DEFAULT NULL,
`f2` char(20) DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) SUBPARTITIONS 2 (PARTITION part1 VALUES LESS THAN (100) , PARTITION part2 VALUES LESS THAN (2147483647) )
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) SUBPARTITIONS 2 (PARTITION part1 VALUES LESS THAN (100) ENGINE = MyISAM, PARTITION part2 VALUES LESS THAN (2147483647) ENGINE = MyISAM)
SELECT COUNT(*) = 0 AS my_value FROM t1;
my_value
1
@@ -1098,7 +1098,7 @@ Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) DEFAULT NULL,
`f2` char(20) DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) SUBPARTITIONS 1 (PARTITION part1 VALUES LESS THAN (100) , PARTITION part2 VALUES LESS THAN (2147483647) )
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) SUBPARTITIONS 1 (PARTITION part1 VALUES LESS THAN (100) ENGINE = MyISAM, PARTITION part2 VALUES LESS THAN (2147483647) ENGINE = MyISAM)
SELECT COUNT(*) = 0 AS my_value FROM t1;
my_value
1
diff --git a/mysql-test/r/partition_error.result b/mysql-test/r/partition_error.result
index 1a0b1dd9b3a..a7ca3d9b2fa 100644
--- a/mysql-test/r/partition_error.result
+++ b/mysql-test/r/partition_error.result
@@ -554,3 +554,26 @@ PARTITION BY RANGE (a) (PARTITION p1 VALUES LESS THAN(5));
insert into t1 values (10);
ERROR HY000: Table has no partition for value 10
drop table t1;
+create table t1 (v varchar(12))
+partition by range (ascii(v))
+(partition p0 values less than (10));
+drop table t1;
+create table t1 (a int)
+partition by hash (rand(a));
+ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2
+create table t1 (a int)
+partition by hash(CURTIME() + a);
+ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2
+create table t1 (a int)
+partition by hash (NOW()+a);
+ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2
+create table t1 (a int)
+partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00')));
+ERROR HY000: This partition function is not allowed
+create table t1 (a int)
+partition by range (a + (select count(*) from t1))
+(partition p1 values less than (1));
+ERROR HY000: This partition function is not allowed
+create table t1 (a char(10))
+partition by hash (extractvalue(a,'a'));
+ERROR HY000: The PARTITION function returns the wrong type
diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result
index 405cc3e6e25..950a83c6d4f 100644
--- a/mysql-test/r/partition_pruning.result
+++ b/mysql-test/r/partition_pruning.result
@@ -670,3 +670,30 @@ select * from t1 where a like 'n%';
a
na
drop table t1;
+create table t1 (s1 varchar(15)) partition by key (s1);
+select * from t1 where s1 = 0 or s1 is null;
+s1
+insert into t1 values ('aa'),('bb'),('0');
+explain partitions select * from t1 where s1 = 0 or s1 is null;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 3 Using where
+drop table t1;
+create table t2 (a int, b int)
+partition by LIST(a)
+subpartition by HASH(b) subpartitions 40
+( partition p_0_long_partition_name values in(1),
+partition p_1_long_partition_name values in(2));
+insert into t2 values (1,1),(2,2);
+explain partitions select * from t2;
+id 1
+select_type SIMPLE
+table t2
+partitions p_0_long_partition_name_p_0_long_partition_namesp0,p_0_long_partition_name_p_0_long_partition_namesp1,p_0_long_partition_name_p_0_long_partition_namesp2,p_0_long_partition_name_p_0_long_partition_namesp3,p_0_long_partition_name_p_0_long_partition_namesp4,p_0_long_partition_name_p_0_long_partition_namesp5,p_0_long_partition_name_p_0_long_partition_namesp6,p_0_long_partition_name_p_0_long_partition_namesp7,p_0_long_partition_name_p_0_long_partition_namesp8,p_0_long_partition_name_p_0_long_partition_namesp9,p_0_long_partition_name_p_0_long_partition_namesp10,p_0_long_partition_name_p_0_long_partition_namesp11,p_0_long_partition_name_p_0_long_partition_namesp12,p_0_long_partition_name_p_0_long_partition_namesp13,p_0_long_partition_name_p_0_long_partition_namesp14,p_0_long_partition_name_p_0_long_partition_namesp15,p_0_long_partition_name_p_0_long_partition_namesp16,p_0_long_partition_name_p_0_long_partition_namesp17,p_0_long_partition_name_p_0_long_partition_namesp18,p_0_long_partition_name_p_0_long_partition_namesp19,p_0_long_partition_name_p_0_long_partition_namesp20,p_0_long_partition_name_p_0_long_partition_namesp21,p_0_long_partition_name_p_0_long_partition_namesp22,p_0_long_partition_name_p_0_long_partition_namesp23,p_0_long_partition_name_p_0_long_partition_namesp24,p_0_long_partition_name_p_0_long_partition_namesp25,p_0_long_partition_name_p_0_long_partition_namesp26,p_0_long_partition_name_p_0_long_partition_namesp27,p_0_long_partition_name_p_0_long_partition_namesp28,p_0_long_partition_name_p_0_long_partition_namesp29,p_0_long_partition_name_p_0_long_partition_namesp30,p_0_long_partition_name_p_0_long_partition_namesp31,p_0_long_partition_name_p_0_long_partition_namesp32,p_0_long_partition_name_p_0_long_partition_namesp33,p_0_long_partition_name_p_0_long_partition_namesp34,p_0_long_partition_name_p_0_long_partition_namesp35,p_0_long_partition_name_p_0_long_partition_namesp36,p_0_long_partition_name_p_0_long_partition_namesp37,p_0_long_partition_name_p_0_long_partition_namesp38,p_0_long_partition_name_p_0_long_partition_namesp39,p_1_long_partition_name_p_1_long_partition_namesp0,p_1_long_partition_name_p_1_long_partition_namesp1,p_1_long_partition_name_p_1_long_partition_namesp2,p_1_long_partition_name_p_1_long_partition_namesp3,p_1_long_partition_name_p_1_long_partition_namesp4,p_1_long_partition_name_p_1_long_partition_namesp5,p_1_long_partition_name_p_1_long_partition_namesp6,p_1_long_partition_name_p_1_long_partition_namesp7,p_1_long_partition_name_p_1_long_partition_namesp8,p_1_long_partition_name_p_1_long_partition_namesp9,p_1_long_partition_name_p_1_long_partition_namesp10,p_1_long_partition_name_p_1_long_partition_namesp11,p_1_long_partition_name_p_1_long_partition_namesp12,p_1_long_partition_name_p_1_long_partition_namesp13,p_1_long_partition_name_p_1_long_partition_namesp14,p_1_long_partition_name_p_1_long_partition_namesp15,p_1_long_partition_name_p_1_long_partition_namesp16,p_1_long_partition_name_p_1_long_partition_namesp17,p_1_long_partition_name_p_1_long_partition_namesp18,p_1_long_partition_name_p_1_long_partition_namesp19,p_1_long_partition_name_p_1_long_partition_namesp20,p_1_long_partition_name_p_1_long_partition_namesp21,p_1_long_partition_name_p_1_long_partition_namesp22,p_1_long_partition_name_p_1_long_partition_namesp23,p_1_long_partition_name_p_1_long_partition_namesp24,p_1_long_partition_name_p_1_long_partition_namesp25,p_1_long_partition_name_p_1_long_partition_namesp26,p_1_long_partition_name_p_1_long_partition_namesp27,p_1_long_partition_name_p_1_long_partition_namesp28,p_1_long_partition_name_p_1_long_partition_namesp29,p_1_long_partition_name_p_1_long_partition_namesp30,p_1_long_partition_name_p_1_long_partition_namesp31,p_1_long_partition_name_p_1_long_partition_namesp32,p_1_long_partition_name_p_1_long_partition_namesp33,p_1_long_partition_name_p_1_long_partition_namesp34,p_1_long_partition_name_p_1_long_partition_namesp35,p_1_long_partition_name_p_1_long_partition_namesp36,p_1_long_partition_name_p_1_long_partition_namesp37,p_1_long_partition_name_p_1_long_partition_namesp38,p_1_long_partition_name_p_1_long_partition_namesp39
+type ALL
+possible_keys NULL
+key NULL
+key_len NULL
+ref NULL
+rows 2
+Extra
+drop table t2;
diff --git a/mysql-test/r/preload.result b/mysql-test/r/preload.result
index b668b07b398..145fd22ffb6 100644
--- a/mysql-test/r/preload.result
+++ b/mysql-test/r/preload.result
@@ -160,11 +160,11 @@ Key_reads 0
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.t2 preload_keys error Key column 'c' doesn't exist in table
+test.t2 preload_keys error Key 'c' doesn't exist in table 't2'
test.t2 preload_keys status Operation failed
Warnings:
Error 1146 Table 'test.t3' doesn't exist
-Error 1072 Key column 'c' doesn't exist in table
+Error 1176 Key 'c' doesn't exist in table 't2'
show status like "key_read%";
Variable_name Value
Key_read_requests 0
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index d0b773dfe34..1a1d6432411 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -299,7 +299,7 @@ t9 MyISAM 10 Dynamic 2 216 432 # 2048 0 NULL # # # latin1_swedish_ci NULL
prepare stmt4 from ' show status like ''Threads_running'' ';
execute stmt4;
Variable_name Value
-Threads_running 1
+Threads_running 2
prepare stmt4 from ' show variables like ''sql_mode'' ';
execute stmt4;
Variable_name Value
diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result
index e828f2c1e31..cfa2b4dc76d 100644
--- a/mysql-test/r/rpl_ddl.result
+++ b/mysql-test/r/rpl_ddl.result
@@ -359,8 +359,6 @@ MAX(f1)
-------- switch to master -------
ROLLBACK;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
SELECT MAX(f1) FROM t1;
MAX(f1)
5
@@ -579,8 +577,6 @@ MAX(f1)
-------- switch to master -------
ROLLBACK;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
SELECT MAX(f1) FROM t1;
MAX(f1)
8
diff --git a/mysql-test/r/rpl_ndb_2myisam.result b/mysql-test/r/rpl_ndb_2myisam.result
index 00fb2f5455f..8611d83f3f3 100644
--- a/mysql-test/r/rpl_ndb_2myisam.result
+++ b/mysql-test/r/rpl_ndb_2myisam.result
@@ -27,7 +27,7 @@ t1 CREATE TABLE `t1` (
`y` year(4) DEFAULT NULL,
`t` date DEFAULT NULL,
PRIMARY KEY (`id`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY ()
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Show table on slave ---
SHOW CREATE TABLE t1;
Table Create Table
@@ -100,7 +100,7 @@ t1 CREATE TABLE `t1` (
`y` year(4) DEFAULT NULL,
`t` date DEFAULT NULL,
PRIMARY KEY (`id`,`total`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY ()
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Make sure that our tables on slave are still same engine ---
--- and that the alter statements replicated correctly ---
SHOW CREATE TABLE t1;
diff --git a/mysql-test/r/rpl_ndb_dd_partitions.result b/mysql-test/r/rpl_ndb_dd_partitions.result
deleted file mode 100644
index ece6b84c227..00000000000
--- a/mysql-test/r/rpl_ndb_dd_partitions.result
+++ /dev/null
@@ -1,726 +0,0 @@
-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;
---- Doing pre test cleanup ---
-DROP TABLE IF EXISTS t1;
-CREATE LOGFILE GROUP lg1
-ADD UNDOFILE 'undofile.dat'
-INITIAL_SIZE 16M
-UNDO_BUFFER_SIZE = 1M
-ENGINE=NDB;
-ALTER LOGFILE GROUP lg1
-ADD UNDOFILE 'undofile02.dat'
-INITIAL_SIZE = 4M
-ENGINE=NDB;
-CREATE TABLESPACE ts1
-ADD DATAFILE 'datafile.dat'
-USE LOGFILE GROUP lg1
-INITIAL_SIZE 12M
-ENGINE NDB;
-ALTER TABLESPACE ts1
-ADD DATAFILE 'datafile02.dat'
-INITIAL_SIZE = 4M
-ENGINE=NDB;
---- Start test 2 partition RANGE testing --
---- Do setup --
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
-bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
-f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
-y YEAR, t DATE)
-TABLESPACE ts1 STORAGE DISK
-ENGINE=NDB
-PARTITION BY RANGE (YEAR(t))
-(PARTITION p0 VALUES LESS THAN (1901),
-PARTITION p1 VALUES LESS THAN (1946),
-PARTITION p2 VALUES LESS THAN (1966),
-PARTITION p3 VALUES LESS THAN (1986),
-PARTITION p4 VALUES LESS THAN (2005),
-PARTITION p5 VALUES LESS THAN MAXVALUE);
---- Show table on master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster)
---- Show table on slave --
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster)
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- Check that simple Alter statements are replicated correctly ---
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
---- Show the new improved table on the master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster)
---- Make sure that our tables on slave are still same engine ---
---- and that the alter statements replicated correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster)
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- End test 2 partition RANGE testing ---
---- Do Cleanup ---
-DROP TABLE IF EXISTS t1;
---- Start test 3 partition LIST testing ---
---- Do setup ---
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
-bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
-f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
-y YEAR, t DATE)
-TABLESPACE ts1 STORAGE DISK
-ENGINE=NDB
-PARTITION BY LIST(id)
-(PARTITION p0 VALUES IN (2, 4),
-PARTITION p1 VALUES IN (42, 142));
---- Test 3 Alter to add partition ---
-ALTER TABLE t1 ADD PARTITION (PARTITION p2 VALUES IN (412));
---- Show table on master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster)
---- Show table on slave ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster)
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- Check that simple Alter statements are replicated correctly ---
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
---- Show the new improved table on the master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster)
---- Make sure that our tables on slave are still same engine ---
---- and that the alter statements replicated correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster)
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- End test 3 partition LIST testing ---
---- Do Cleanup --
-DROP TABLE IF EXISTS t1;
---- Start test 4 partition HASH testing ---
---- Do setup ---
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
-bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
-f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
-y YEAR, t DATE)
-TABLESPACE ts1 STORAGE DISK
-ENGINE=NDB
-PARTITION BY HASH( YEAR(t) )
-PARTITIONS 4;
---- show that tables have been created correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- Check that simple Alter statements are replicated correctly ---
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
---- Show the new improved table on the master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4
---- Make sure that our tables on slave are still same engine ---
---- and that the alter statements replicated correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- End test 4 partition HASH testing ---
---- Do Cleanup --
-DROP TABLE IF EXISTS t1;
---- Start test 5 partition by key testing ---
---- Create Table Section ---
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
-bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
-f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
-y YEAR, t DATE,PRIMARY KEY(id))
-TABLESPACE ts1 STORAGE DISK
-ENGINE=NDB
-PARTITION BY KEY()
-PARTITIONS 4;
---- Show that tables on master are ndbcluster tables ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`)
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Show that tables on slave ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned DEFAULT NULL,
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`)
-) TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- Check that simple Alter statements are replicated correctly ---
-ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total);
---- Show the new improved table on the master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned NOT NULL DEFAULT '0',
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`,`total`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Make sure that our tables on slave are still right type ---
---- and that the alter statements replicated correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(63) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned NOT NULL DEFAULT '0',
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`,`total`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- Check that simple Alter statements are replicated correctly ---
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
---- Show the new improved table on the master ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned NOT NULL DEFAULT '0',
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`,`total`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Make sure that our tables on slave are still same engine ---
---- and that the alter statements replicated correctly ---
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `id` mediumint(9) NOT NULL,
- `b1` bit(8) DEFAULT NULL,
- `vc` varchar(255) DEFAULT NULL,
- `bc` char(63) DEFAULT NULL,
- `d` decimal(10,4) DEFAULT '0.0000',
- `f` float DEFAULT '0',
- `total` bigint(20) unsigned NOT NULL DEFAULT '0',
- `y` year(4) DEFAULT NULL,
- `t` date DEFAULT NULL,
- PRIMARY KEY (`id`,`total`)
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4
---- Perform basic operation on master ---
---- and ensure replicated correctly ---
-"--- Insert into t1 --" as "";
---- Select from t1 on master ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Select from t1 on slave ---
-select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
-id hex(b1) vc bc d f total y t
-2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14
-4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14
-42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14
-142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14
-412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14
---- Update t1 on master --
-UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
---- Check the update on master ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Check Update on slave ---
-SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
-id hex(b1) vc bc d f total y t
-412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22
---- Remove a record from t1 on master ---
-DELETE FROM t1 WHERE id = 42;
---- Show current count on master for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
---- Show current count on slave for t1 ---
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-4
-DELETE FROM t1;
---- End test 5 key partition testing ---
---- Do Cleanup ---
-DROP TABLE IF EXISTS t1;
-alter tablespace ts1
-drop datafile 'datafile.dat'
-engine=ndb;
-alter tablespace ts1
-drop datafile 'datafile02.dat'
-engine=ndb;
-DROP TABLESPACE ts1 ENGINE=NDB;
-DROP LOGFILE GROUP lg1 ENGINE=NDB;
diff --git a/mysql-test/r/rpl_ndb_log.result b/mysql-test/r/rpl_ndb_log.result
index 5f6f040b715..c435fb37531 100644
--- a/mysql-test/r/rpl_ndb_log.result
+++ b/mysql-test/r/rpl_ndb_log.result
@@ -47,6 +47,10 @@ master-bin.000001 # Table_map 1 # table_id: # (test.t1)
flush logs;
create table t3 (a int)ENGINE=NDB;
start slave;
+
+let $result_pattern= '%127.0.0.1%root%master-bin.000002%slave-relay-bin.000005%Yes%Yes%0%0%None%' ;
+
+--source include/wait_slave_status.inc
flush logs;
stop slave;
create table t2 (n int)ENGINE=NDB;
diff --git a/mysql-test/r/rpl_stm_until.result b/mysql-test/r/rpl_stm_until.result
index 11b69f55f82..e8e33b66864 100644
--- a/mysql-test/r/rpl_stm_until.result
+++ b/mysql-test/r/rpl_stm_until.result
@@ -19,9 +19,40 @@ n
2
3
4
-show slave status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 # No 0 0 323 # Master master-bin.000001 323 No #
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_MYPORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 780
+Relay_Log_File slave-relay-bin.000004
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running #
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 323
+Relay_Log_Space #
+Until_Condition Master
+Until_Log_File master-bin.000001
+Until_Log_Pos 323
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291;
select * from t1;
n
@@ -29,23 +60,116 @@ n
2
3
4
-show slave status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 # No 0 0 323 # Master master-no-such-bin.000001 291 No #
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_MYPORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 780
+Relay_Log_File slave-relay-bin.000004
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running #
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 323
+Relay_Log_Space #
+Until_Condition Master
+Until_Log_File master-no-such-bin.000001
+Until_Log_Pos 291
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
select * from t2;
n
1
2
-show slave status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 # No 0 0 612 # Relay slave-relay-bin.000004 746 No #
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_MYPORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 780
+Relay_Log_File slave-relay-bin.000004
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running #
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 612
+Relay_Log_Space #
+Until_Condition Relay
+Until_Log_File slave-relay-bin.000004
+Until_Log_Pos 746
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
start slave;
stop slave;
start slave until master_log_file='master-bin.000001', master_log_pos=776;
-show slave status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 780 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 780 # Master master-bin.000001 776 No #
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_MYPORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 780
+Relay_Log_File slave-relay-bin.000004
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 780
+Relay_Log_Space #
+Until_Condition Master
+Until_Log_File master-bin.000001
+Until_Log_Pos 776
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
start slave until master_log_file='master-bin', master_log_pos=561;
ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL
start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12;
diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result
index 7f6fa17e11c..01882c683a4 100644
--- a/mysql-test/r/rpl_temporary.result
+++ b/mysql-test/r/rpl_temporary.result
@@ -88,15 +88,23 @@ f
1
drop temporary table t4;
drop table t5;
-set @session.pseudo_thread_id=100;
+set @@session.pseudo_thread_id=100;
create temporary table t101 (id int);
create temporary table t102 (id int);
-set @session.pseudo_thread_id=200;
+set @@session.pseudo_thread_id=200;
create temporary table t201 (id int);
-create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
+create temporary table `#sql_not_user_table202` (id int);
+set @@session.pseudo_thread_id=300;
+create temporary table t301 (id int);
+create temporary table t302 (id int);
+create temporary table `#sql_not_user_table303` (id int);
create table t1(f int);
insert into t1 values (1);
select * from t1 /* must be 1 */;
f
1
drop table t1;
+select * from t1;
+a
+1
+drop table t1;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index f45e16f66c1..d47d49b5298 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -144,9 +144,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index
explain select fld3 from t2 ignore index (fld3,not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
explain select fld3 from t2 use index (not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
fld3
honeysuckle
@@ -2716,6 +2716,16 @@ select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 fro
f1 f2
1 1
drop table t1,t2;
+CREATE TABLE t1 (a int, INDEX idx(a));
+INSERT INTO t1 VALUES (2), (3), (1);
+EXPLAIN SELECT * FROM t1 IGNORE INDEX (idx);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+EXPLAIN SELECT * FROM t1 IGNORE INDEX (a);
+ERROR 42000: Key 'a' doesn't exist in table 't1'
+EXPLAIN SELECT * FROM t1 FORCE INDEX (a);
+ERROR 42000: Key 'a' doesn't exist in table 't1'
+DROP TABLE t1;
CREATE TABLE t1 ( city char(30) );
INSERT INTO t1 VALUES ('London');
INSERT INTO t1 VALUES ('Paris');
diff --git a/mysql-test/r/skip_name_resolve.result b/mysql-test/r/skip_name_resolve.result
index 8ef52e75238..855876825ad 100644
--- a/mysql-test/r/skip_name_resolve.result
+++ b/mysql-test/r/skip_name_resolve.result
@@ -10,5 +10,6 @@ user()
#
show processlist;
Id User Host db Command Time State Info
+<id> event_scheduler <host> NULL <command> <time> <state> <info>
<id> root <host> test <command> <time> <state> <info>
<id> root <host> test <command> <time> <state> <info>
diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result
index c516d7a643f..3cba437e0a6 100644
--- a/mysql-test/r/sp-threads.result
+++ b/mysql-test/r/sp-threads.result
@@ -34,6 +34,7 @@ lock tables t2 write;
call bug9486();
show processlist;
Id User Host db Command Time State Info
+# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Sleep # NULL
# root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2
# root localhost test Query # NULL show processlist
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 2511beb47d3..17145619f0f 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -4954,4 +4954,34 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DROP FUNCTION bug18589_f1|
DROP PROCEDURE bug18589_p1|
DROP PROCEDURE bug18589_p2|
+DROP FUNCTION IF EXISTS bug18037_f1|
+DROP PROCEDURE IF EXISTS bug18037_p1|
+DROP PROCEDURE IF EXISTS bug18037_p2|
+CREATE FUNCTION bug18037_f1() RETURNS INT
+BEGIN
+RETURN @@server_id;
+END|
+CREATE PROCEDURE bug18037_p1()
+BEGIN
+DECLARE v INT DEFAULT @@server_id;
+END|
+CREATE PROCEDURE bug18037_p2()
+BEGIN
+CASE @@server_id
+WHEN -1 THEN
+SELECT 0;
+ELSE
+SELECT 1;
+END CASE;
+END|
+SELECT bug18037_f1()|
+bug18037_f1()
+1
+CALL bug18037_p1()|
+CALL bug18037_p2()|
+1
+1
+DROP FUNCTION bug18037_f1|
+DROP PROCEDURE bug18037_p1|
+DROP PROCEDURE bug18037_p2|
drop table t1,t2;
diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result
index c8cafe5ace1..c5d60446e0a 100644
--- a/mysql-test/r/sp_notembedded.result
+++ b/mysql-test/r/sp_notembedded.result
@@ -18,9 +18,11 @@ show processlist;
end|
call bug4902_2()|
Id User Host db Command Time State Info
+# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Query # NULL show processlist
call bug4902_2()|
Id User Host db Command Time State Info
+# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Query # NULL show processlist
drop procedure bug4902_2|
drop function if exists bug5278|
diff --git a/mysql-test/r/ssl.result b/mysql-test/r/ssl.result
index bb7297d6807..c5df9e99de6 100644
--- a/mysql-test/r/ssl.result
+++ b/mysql-test/r/ssl.result
@@ -145,9 +145,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index
explain select fld3 from t2 ignore index (fld3,not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
explain select fld3 from t2 use index (not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
fld3
honeysuckle
diff --git a/mysql-test/r/ssl_compress.result b/mysql-test/r/ssl_compress.result
index 9c1cf4b0ec3..c7919c7e424 100644
--- a/mysql-test/r/ssl_compress.result
+++ b/mysql-test/r/ssl_compress.result
@@ -148,9 +148,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index
explain select fld3 from t2 ignore index (fld3,not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
explain select fld3 from t2 use index (not_used);
-ERROR 42000: Key column 'not_used' doesn't exist in table
+ERROR 42000: Key 'not_used' doesn't exist in table 't2'
select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3;
fld3
honeysuckle
diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result
index ca21b333a6a..e83ade78cf6 100644
--- a/mysql-test/r/status.result
+++ b/mysql-test/r/status.result
@@ -26,20 +26,20 @@ Last_query_cost 0.000000
FLUSH STATUS;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
-Max_used_connections 1
+Max_used_connections 2
SET @save_thread_cache_size=@@thread_cache_size;
SET GLOBAL thread_cache_size=3;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
-Max_used_connections 3
+Max_used_connections 4
FLUSH STATUS;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
-Max_used_connections 2
-SHOW STATUS LIKE 'max_used_connections';
-Variable_name Value
Max_used_connections 3
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 4
+SHOW STATUS LIKE 'max_used_connections';
+Variable_name Value
+Max_used_connections 5
SET GLOBAL thread_cache_size=@save_thread_cache_size;
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
index 92f1ba3a23e..5ca185d6abc 100644
--- a/mysql-test/r/strict.result
+++ b/mysql-test/r/strict.result
@@ -1288,3 +1288,13 @@ ERROR 22001: Data too long for column 'a' at row 1
select * from t1;
a
drop table t1;
+set sql_mode='traditional';
+create table t1 (date date not null);
+create table t2 select date from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `date` date NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2,t1;
+set @@sql_mode= @org_mode;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 07f740687ca..e307bb9eafe 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -3177,3 +3177,30 @@ ERROR 42S22: Unknown column 'no_such_column' in 'where clause'
SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1);
ERROR 42S22: Unknown column 'no_such_column' in 'IN/ALL/ANY subquery'
DROP TABLE t1;
+create table t1 (i int, j bigint);
+insert into t1 values (1, 2), (2, 2), (3, 2);
+select * from (select min(i) from t1 where j=(select * from (select min(j) from t1) t2)) t3;
+min(i)
+1
+drop table t1;
+CREATE TABLE t1 (i BIGINT UNSIGNED);
+INSERT INTO t1 VALUES (10000000000000000000);
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 (i BIGINT UNSIGNED);
+INSERT INTO t2 VALUES (10000000000000000000);
+INSERT INTO t2 VALUES (1);
+/* simple test */
+SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i;
+i
+10000000000000000000
+1
+/* subquery test */
+SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2);
+i
+10000000000000000000
+/* subquery test with cast*/
+SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED);
+i
+10000000000000000000
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result
index 30cde39531d..b9d3504993c 100644
--- a/mysql-test/r/system_mysql_db.result
+++ b/mysql-test/r/system_mysql_db.result
@@ -208,7 +208,7 @@ event CREATE TABLE `event` (
`on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP',
`sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '',
`comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
- PRIMARY KEY (`definer`,`db`,`name`)
+ PRIMARY KEY (`db`,`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
show create table general_log;
Table Create Table
diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result
index 0ba8916f5b1..ba401a22945 100644
--- a/mysql-test/r/type_ranges.result
+++ b/mysql-test/r/type_ranges.result
@@ -241,7 +241,7 @@ Field Type Collation Null Key Default Extra Privileges Comment
auto int(5) unsigned NULL NO 0 #
string char(10) latin1_swedish_ci YES newdefault #
tiny tinyint(4) NULL NO 0 #
-short smallint(6) NULL NO 0 #
+short smallint(6) NULL NO #
medium mediumint(8) NULL NO 0 #
long_int int(11) NULL NO 0 #
longlong bigint(13) NULL NO 0 #
@@ -259,7 +259,7 @@ date_time datetime NULL YES NULL #
new_blob_col varchar(20) latin1_swedish_ci YES NULL #
tinyblob_col tinyblob NULL YES NULL #
mediumblob_col mediumblob NULL NO #
-options enum('one','two','tree') latin1_swedish_ci NO one #
+options enum('one','two','tree') latin1_swedish_ci NO #
flags set('one','two','tree') latin1_swedish_ci NO #
new_field char(10) latin1_swedish_ci NO new #
select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null)));
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index 9516a859bad..e4b3fc2c2e2 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -639,6 +639,35 @@ select @@version, @@version_comment, @@version_compile_machine,
@@version_compile_os;
@@version @@version_comment @@version_compile_machine @@version_compile_os
# # # #
+select @@basedir, @@datadir, @@tmpdir;
+@@basedir @@datadir @@tmpdir
+# # #
+show variables like 'basedir';
+Variable_name Value
+basedir #
+show variables like 'datadir';
+Variable_name Value
+datadir #
+show variables like 'tmpdir';
+Variable_name Value
+tmpdir #
+select @@ssl_ca, @@ssl_capath, @@ssl_cert, @@ssl_cipher, @@ssl_key;
+@@ssl_ca @@ssl_capath @@ssl_cert @@ssl_cipher @@ssl_key
+# # # # #
+show variables like 'ssl%';
+Variable_name Value
+ssl_ca #
+ssl_capath #
+ssl_cert #
+ssl_cipher #
+ssl_key #
+select @@log_queries_not_using_indexes;
+@@log_queries_not_using_indexes
+0
+show variables like 'log_queries_not_using_indexes';
+Variable_name Value
+log_queries_not_using_indexes OFF
+End of 5.0 tests
set global binlog_cache_size =@my_binlog_cache_size;
set global connect_timeout =@my_connect_timeout;
set global delayed_insert_timeout =@my_delayed_insert_timeout;
@@ -666,4 +695,3 @@ set global server_id =@my_server_id;
set global slow_launch_time =@my_slow_launch_time;
set global storage_engine =@my_storage_engine;
set global thread_cache_size =@my_thread_cache_size;
-End of 5.0 tests
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 795638dced0..9fabb0ad2d8 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -614,7 +614,7 @@ drop table t1;
create table t1 (a int, b int);
create view v1 as select a, sum(b) from t1 group by a;
select b from v1 use index (some_index) where b=1;
-ERROR 42000: Key column 'some_index' doesn't exist in table
+ERROR 42000: Key 'some_index' doesn't exist in table 'v1'
drop view v1;
drop table t1;
create table t1 (col1 char(5),col2 char(5));
@@ -2660,3 +2660,79 @@ SELECT * FROM v1;
id t COUNT(*)
DROP VIEW v1;
DROP TABLE t1;
+CREATE TABLE t1 (i INT, j BIGINT);
+INSERT INTO t1 VALUES (1, 2), (2, 2), (3, 2);
+CREATE VIEW v1 AS SELECT MIN(j) AS j FROM t1;
+CREATE VIEW v2 AS SELECT MIN(i) FROM t1 WHERE j = ( SELECT * FROM v1 );
+SELECT * FROM v2;
+MIN(i)
+1
+DROP VIEW v2, v1;
+DROP TABLE t1;
+CREATE TABLE t1(
+fName varchar(25) NOT NULL,
+lName varchar(25) NOT NULL,
+DOB date NOT NULL,
+uID int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY);
+INSERT INTO t1(fName, lName, DOB) VALUES
+('Hank', 'Hill', '1964-09-29'),
+('Tom', 'Adams', '1908-02-14'),
+('Homer', 'Simpson', '1968-03-05');
+CREATE VIEW v1 AS
+SELECT (year(now())-year(DOB)) AS Age
+FROM t1 HAVING Age < 75;
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache (year(now()) - year(`t1`.`DOB`)) AS `Age` from `t1` having (`Age` < 75)
+SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75;
+Age
+42
+38
+SELECT * FROM v1;
+Age
+42
+38
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx');
+INSERT INTO t1(id) VALUES (1), (2), (3), (4);
+INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy');
+SELECT * FROM t1;
+id a
+1 xxx
+2 xxx
+3 xxx
+4 xxx
+5 yyy
+6 yyy
+CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a;
+SELECT * FROM v1;
+a m
+xxx 1
+yyy 5
+CREATE TABLE t2 SELECT * FROM v1;
+INSERT INTO t2(m) VALUES (0);
+SELECT * FROM t2;
+a m
+xxx 1
+yyy 5
+xxx 0
+DROP VIEW v1;
+DROP TABLE t1,t2;
+CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b');
+INSERT INTO t1(id) VALUES (1), (2), (3);
+INSERT INTO t1 VALUES (4,'a');
+SELECT * FROM t1;
+id e
+1 b
+2 b
+3 b
+4 a
+CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e;
+CREATE TABLE t2 SELECT * FROM v1;
+SELECT * FROM t2;
+m e
+4 a
+1 b
+DROP VIEW v1;
+DROP TABLE IF EXISTS t1,t2;
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index 928e3635ec6..db82016f398 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -1,5 +1,5 @@
drop database if exists mysqltest;
-drop view if exists v1;
+drop view if exists v1,v2,v3;
grant create view on test.* to test@localhost;
show grants for test@localhost;
Grants for test@localhost
@@ -535,3 +535,88 @@ View Create View
v2 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select 1 AS `1`
drop view v1;
drop view v2;
+CREATE DATABASE mysqltest1;
+CREATE USER readonly@localhost;
+CREATE TABLE mysqltest1.t1 (x INT);
+INSERT INTO mysqltest1.t1 VALUES (1), (2);
+CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1;
+GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly;
+GRANT SELECT ON mysqltest1.v_ts TO readonly;
+GRANT INSERT ON mysqltest1.v_ti TO readonly;
+GRANT UPDATE ON mysqltest1.v_tu TO readonly;
+GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly;
+GRANT DELETE ON mysqltest1.v_td TO readonly;
+GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly;
+SELECT * FROM mysqltest1.v_t1;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+INSERT INTO mysqltest1.v_t1 VALUES(4);
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+DELETE FROM mysqltest1.v_t1 WHERE x = 1;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+UPDATE mysqltest1.v_t1 SET x = 3;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+DELETE FROM mysqltest1.v_t1;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+SELECT 1 FROM mysqltest1.v_t1;
+ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+SELECT * FROM mysqltest1.t1;
+ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1'
+SELECT * FROM mysqltest1.v_ts;
+x
+1
+2
+SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x;
+ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1'
+SELECT * FROM mysqltest1.v_ti;
+ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 'v_ti'
+INSERT INTO mysqltest1.v_ts VALUES (100);
+ERROR 42000: INSERT command denied to user 'readonly'@'localhost' for table 'v_ts'
+INSERT INTO mysqltest1.v_ti VALUES (100);
+UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100;
+ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts'
+UPDATE mysqltest1.v_ts SET x= 200;
+ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts'
+UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100;
+UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100;
+UPDATE mysqltest1.v_tu SET x= 200;
+DELETE FROM mysqltest1.v_ts WHERE x= 200;
+ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts'
+DELETE FROM mysqltest1.v_ts;
+ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts'
+DELETE FROM mysqltest1.v_td WHERE x= 200;
+ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for column 'x' in table 'v_td'
+DELETE FROM mysqltest1.v_tds WHERE x= 200;
+DELETE FROM mysqltest1.v_td;
+DROP VIEW mysqltest1.v_tds;
+DROP VIEW mysqltest1.v_td;
+DROP VIEW mysqltest1.v_tus;
+DROP VIEW mysqltest1.v_tu;
+DROP VIEW mysqltest1.v_ti;
+DROP VIEW mysqltest1.v_ts;
+DROP VIEW mysqltest1.v_t1;
+DROP TABLE mysqltest1.t1;
+DROP USER readonly@localhost;
+DROP DATABASE mysqltest1;
+CREATE TABLE t1 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1;
+Warnings:
+Note 1449 There is no 'no-such-user'@'localhost' registered
+SHOW CREATE VIEW v;
+View Create View
+v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `t1`.`a` AS `a` from `t1`
+Warnings:
+Note 1449 There is no 'no-such-user'@'localhost' registered
+SELECT * FROM v;
+ERROR HY000: There is no 'no-such-user'@'localhost' registered
+DROP VIEW v;
+DROP TABLE t1;
+USE test;
diff --git a/mysql-test/std_data/bug15328.cnf b/mysql-test/std_data/bug15328.cnf
new file mode 100644
index 00000000000..e23d33bfa54
--- /dev/null
+++ b/mysql-test/std_data/bug15328.cnf
@@ -0,0 +1,2 @@
+[mysqldump]
+fields-optionally-enclosed-by="
diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test
index 7e091991475..c89d31c69b9 100644
--- a/mysql-test/t/archive.test
+++ b/mysql-test/t/archive.test
@@ -5,7 +5,7 @@
-- source include/have_archive.inc
--disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
--enable_warnings
CREATE TABLE t1 (
diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test
index 26b103b0107..e0b024d021b 100644
--- a/mysql-test/t/auto_increment.test
+++ b/mysql-test/t/auto_increment.test
@@ -275,3 +275,14 @@ update t1 set a=2 where a=1;
insert into t1 (val) values (1);
select * from t1;
drop table t1;
+
+#
+# Test key duplications with auto-increment in ALTER TABLE
+# bug #14573
+#
+CREATE TABLE t1 (t1 INT(10) PRIMARY KEY, t2 INT(10));
+INSERT INTO t1 VALUES(0, 0);
+INSERT INTO t1 VALUES(1, 1);
+--error ER_DUP_ENTRY
+ALTER TABLE t1 CHANGE t1 t1 INT(10) auto_increment;
+DROP TABLE t1;
diff --git a/mysql-test/t/contributors.test b/mysql-test/t/contributors.test
new file mode 100644
index 00000000000..e463c4a888b
--- /dev/null
+++ b/mysql-test/t/contributors.test
@@ -0,0 +1 @@
+SHOW CONTRIBUTORS;
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 802987eabc9..b4ba3878580 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -226,6 +226,7 @@ drop table t1;
# Test create table if not exists with duplicate key error
#
+flush status;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
@@ -233,6 +234,8 @@ select * from t1;
create table if not exists t1 select 3 as 'a',4 as 'b';
--error 1062
create table if not exists t1 select 3 as 'a',3 as 'b';
+show warnings;
+show status like "Opened_tables";
select * from t1;
drop table t1;
@@ -669,3 +672,37 @@ drop table t1;
# End of 5.0 tests
+
+#
+# Test of behaviour with CREATE ... SELECT
+#
+
+CREATE TABLE t1 (a int, b int);
+insert into t1 values (1,1),(1,2);
+--error 1062
+CREATE TABLE t2 (primary key (a)) select * from t1;
+# This should give warning
+drop table if exists t2;
+--error 1062
+CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1;
+# This should give warning
+drop table if exists t2;
+CREATE TABLE t2 (a int, b int, primary key (a));
+--error 1062
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+SELECT * from t2;
+TRUNCATE table t2;
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * from t2;
+drop table t2;
+
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a));
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+SELECT * from t2;
+TRUNCATE table t2;
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * from t2;
+drop table t1,t2;
diff --git a/mysql-test/t/ctype_sjis.test b/mysql-test/t/ctype_sjis.test
index 1d807b5e9a8..01e0b334554 100644
--- a/mysql-test/t/ctype_sjis.test
+++ b/mysql-test/t/ctype_sjis.test
@@ -78,6 +78,6 @@ SET collation_connection='sjis_bin';
--character_set sjis
SET NAMES sjis;
-SELECT HEX('²“‘@\Œ\') FROM DUAL;
+SELECT HEX('²“‘@Œ\') FROM DUAL;
# End of 4.1 tests
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 746a117ccd6..96f31133e65 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -9,31 +9,33 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
-events_bugs : BUG#17619 2006-02-21 andrey Race conditions
-events_stress : BUG#17619 2006-02-21 andrey Race conditions
-events : BUG#17619 2006-02-21 andrey Race conditions
-events_scheduling : BUG#19170 2006-04-26 andrey Test case of 19170 fails on some platforms. Has to be checked.
-events_logs_tests : BUG#17619 2006-05-16 andrey Test case problems
+#events_bugs : BUG#17619 2006-02-21 andrey Race conditions
+#events_stress : BUG#17619 2006-02-21 andrey Race conditions
+#events : BUG#17619 2006-02-21 andrey Race conditions
+#events_scheduling : BUG#19170 2006-04-26 andrey Test case of 19170 fails on some platforms. Has to be checked.
+im_instance_conf : Bug#20294 2006-06-06 monty Instance manager test im_instance_conf fails randomly
+im_options : Bug#20294 2006-06-06 monty Instance manager test im_instance_conf fails randomly
+im_life_cycle : Bug#20368 2006-06-10 alik im_life_cycle test fails
ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
-ndb_binlog_discover : BUG#19395 2006-04-28 tomas/knielsen mysqld does not always detect cluster shutdown
+#ndb_binlog_discover : BUG#19395 2006-04-28 tomas/knielsen mysqld does not always detect cluster shutdown
#ndb_cache2 : BUG#18597 2006-03-28 brian simultaneous drop table and ndb statistics update triggers node failure
#ndb_cache_multi2 : BUG#18597 2006-04-10 kent simultaneous drop table and ndb statistics update triggers node failure
ndb_load : BUG#17233 2006-05-04 tomas failed load data from infile causes mysqld dbug_assert, binlog not flushed
partition_03ndb : BUG#16385 2006-03-24 mikael Partitions: crash when updating a range partitioned NDB table
ps_7ndb : BUG#18950 2006-02-16 jmiller create table like does not obtain LOCK_open
rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated
-rpl_ndb_2myisam : BUG#19227 2006-04-20 pekka pk delete apparently not replicated
+rpl_ndb_2myisam : BUG#19227 Seems to pass currently
rpl_ndb_auto_inc : BUG#17086 2006-02-16 jmiller CR: auto_increment_increment and auto_increment_offset produce duplicate key er
-rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with COM_REGISTER_SLAVE error causing stop
+#rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with COM_REGISTER_SLAVE error causing stop
rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD
rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked
-rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
-rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ
-rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
+rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
+#rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ
+rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian
rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly
-rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed
+rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed
rpl_row_inexist_tbl : BUG#18948 2006-03-09 mats Disabled since patch makes this test wait forever
rpl_sp : BUG#16456 2006-02-16 jmiller
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index fbcd4924d56..a3e2bbc0998 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -15,11 +15,10 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
---sleep 2
+--sleep 1.5
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
-SET GLOBAL event_scheduler=0;
---sleep 1
+SET GLOBAL event_scheduler=2;
connection priv_conn;
DROP EVENT e_x1;
DROP EVENT e_x2;
@@ -31,8 +30,7 @@ USE events_test;
#
# END: BUG #17289 Events: missing privilege check for drop database
#
-SET GLOBAL event_scheduler=0;
---sleep 1
+SET GLOBAL event_scheduler=2;
drop event if exists event1;
create event event1 on schedule every 15 minute starts now() ends date_add(now(), interval 5 hour) DO begin end;
alter event event1 rename to event2 enable;
@@ -92,11 +90,11 @@ drop event e_43;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
---sleep 2
+--sleep 1
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
-set global event_scheduler = 0;
+set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
@@ -150,9 +148,9 @@ set names cp1251;
create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
SHOW CREATE EVENT ðóóò21;
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
---error 1235
+--error ER_NOT_SUPPORTED_YET
show create event root22;
---error 1235
+--error ER_NOT_SUPPORTED_YET
SHOW EVENTS;
drop event root22;
drop event root6;
@@ -241,82 +239,6 @@ DROP EVENT intact_check;
# mysql.event intact checking end
#
-#
-#INFORMATION_SCHEMA.EVENTS test begin
-#
-create event one_event on schedule every 10 second do select 123;
---replace_column 8 # 9 #
-SHOW EVENTS;
-SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
-CREATE DATABASE events_test2;
-CREATE USER ev_test@localhost;
-GRANT ALL ON events_test.* to ev_test@localhost;
-GRANT ALL on events_test2.* to ev_test@localhost;
-REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
-REVOKE PROCESS on *.* from ev_test@localhost;
-#now we are on con1
-connect (ev_con1,localhost,ev_test,,events_test2);
-select "NEW CONNECTION";
-SELECT USER(), DATABASE();
-SHOW GRANTS;
-
---echo "Here comes an error:";
-#NO EVENT_ACL on events_test2
---error 1044
-SHOW EVENTS;
-USE events_test;
-
---echo "Now the list should be empty:";
---replace_column 8 # 9 #
-SHOW EVENTS;
-#now create an event with the same name but we are different user
-select concat("Let's create some new events from the name of ",user());
-create event one_event on schedule every 20 second do select 123;
-create event two_event on schedule every 20 second on completion not preserve comment "two event" do select 123;
-create event three_event on schedule every 20 second on completion preserve comment "three event" do select 123;
-
---echo "Now we should see 3 events:";
---replace_column 8 # 9 #
-SHOW EVENTS;
-
---echo "This should show us only 3 events:";
---replace_column 8 # 9 #
-SHOW FULL EVENTS;
-
---echo "This should show us only 2 events:";
---replace_column 8 # 9 #
-SHOW FULL EVENTS LIKE 't%event';
-
---echo "This should show us no events:";
---replace_column 8 # 9 #
-SHOW FULL EVENTS FROM test LIKE '%';
-#ok, we are back
-connection default;
-DROP DATABASE events_test2;
-
---echo "should see 1 event:";
---replace_column 8 # 9 #
-SHOW EVENTS;
-
---echo "we should see 4 events now:";
---replace_column 8 # 9 #
-SHOW FULL EVENTS;
-SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
-
-connection ev_con1;
-drop event one_event;
-drop event two_event;
-drop event three_event;
-disconnect ev_con1;
-connection default;
-drop user ev_test@localhost;
-drop event one_event;
-#
-##INFORMATION_SCHEMA.EVENTS test end
-#
-
---echo "Sleep a bit so the server closes the second connection"
---sleep 2
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
drop event e_26;
@@ -330,21 +252,21 @@ create event задачка on schedule every 123 minute starts now() ends now()
drop event задачка;
# event_scheduler is a global var
---error 1229
-set event_scheduler=0;
-# event_scheduler could be only either 0 or 1
---error 1231
-set global event_scheduler=2;
+--error ER_GLOBAL_VARIABLE
+set event_scheduler=2;
+# event_scheduler could be only either 1 or 2
+--error ER_WRONG_VALUE_FOR_VAR
+set global event_scheduler=3;
--echo "DISABLE the scheduler. Testing that it does not work when the variable is 0"
-set global event_scheduler=0;
+set global event_scheduler=2;
select definer, name, db from mysql.event;
select get_lock("test_lock1", 20);
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
--echo "Should return 1 row"
select definer, name, db from mysql.event;
---echo "Should be 0 processes"
+--echo "Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock("test_lock1");
drop event закачка;
@@ -360,9 +282,9 @@ select get_lock("test_lock2", 20);
--echo "Create an event which tries to acquire a mutex. The event locks on the mutex"
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
--echo "Let some time pass to the event starts"
---sleep 2
+--sleep 1
--echo "Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish."
--echo "Release the mutex, the event worker should finish."
select release_lock("test_lock2");
drop event закачка;
@@ -379,18 +301,11 @@ set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
--sleep 1
---echo "Should see 1 process, locked on get_lock("
-#select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
---echo "Shutting down the scheduler, it should wait for the running event"
-set global event_scheduler=0;
---sleep 1
---echo "Should have only 2 processes: the scheduler and the locked event"
+--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+set global event_scheduler=2;
+--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
---echo "Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
---sleep 1
---echo "Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
drop event закачка21;
####
@@ -426,7 +341,7 @@ drop event white_space;
# END: BUG #17453: Creating Event crash the server
#
-##set global event_scheduler=1;
+#
# Bug#17403 "Events: packets out of order with show create event"
#
create event e1 on schedule every 1 year do set @a = 5;
@@ -440,7 +355,7 @@ drop event e1;
##select get_lock("test_lock3", 20);
##create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
##select sleep(2);
-##show processlist;
+##select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка;
##select release_lock("test_lock3");
@@ -450,14 +365,14 @@ drop event e1;
##select get_lock("test_lock4", 20);
##create event закачка4 on schedule every 1 second do select get_lock("test_lock4", 20);
##select sleep(3);
-##--replace_column 1 # 6 #
+##select /*6*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка4;
##select release_lock("test_lock4");
-##set global event_scheduler=0;
+##set global event_scheduler=2;
##select sleep(2);
##--replace_column 1 # 6 #
+##show processlist;
##select count(*) from mysql.event;
drop database events_test;
-
diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test
index 3f339ff0398..e3b79a6bd13 100644
--- a/mysql-test/t/events_bugs.test
+++ b/mysql-test/t/events_bugs.test
@@ -30,13 +30,13 @@ set @a=3;
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
--echo "Here we used to crash!"
---error 1516
+--error ER_EVENT_ALREADY_EXISTS
call p_16();
---error 1516
+--error ER_EVENT_ALREADY_EXISTS
call p_16();
DROP EVENT e_16;
CALL p_16();
---error 1516
+--error ER_EVENT_ALREADY_EXISTS
CALL p_16();
DROP PROCEDURE p_16;
DROP EVENT e_16;
@@ -47,9 +47,9 @@ DROP EVENT e_16;
#
# Start - 16396: Events: Distant-future dates become past dates
#
---error 1504
+--error ER_WRONG_VALUE
create event e_55 on schedule at 99990101000000 do drop table t;
---error 1504
+--error ER_WRONG_VALUE
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
--error ER_EVENT_ENDS_BEFORE_STARTS
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
@@ -60,7 +60,7 @@ create event e_55 on schedule every 10 minute ends 99990101000000 do drop table
#
# Start - 16407: Events: Changes in sql_mode won't be taken into account
#
-set global event_scheduler=0;
+set global event_scheduler=2;
--echo "Wait a bit to settle down"
--sleep 1
delete from mysql.event;
@@ -79,7 +79,7 @@ delimiter ;|
--echo "Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('test_bug16407');
-set global event_scheduler= 0;
+set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
set sql_mode='traditional';
@@ -121,9 +121,9 @@ set global event_scheduler= 1;
--sleep 1
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
---sleep 3
+--sleep 2
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
-set global event_scheduler= 0;
+set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
--echo "OK, last check before we drop them"
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@@ -156,7 +156,7 @@ set global event_scheduler= 1;
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
---sleep 3
+--sleep 2
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select * from events_smode_test order by ev_name, a;
@@ -166,7 +166,7 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
-set global event_scheduler= 0;
+set global event_scheduler= 2;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
#
diff --git a/mysql-test/t/events_grant.test b/mysql-test/t/events_grant.test
new file mode 100644
index 00000000000..ba94944a3cf
--- /dev/null
+++ b/mysql-test/t/events_grant.test
@@ -0,0 +1,105 @@
+CREATE DATABASE IF NOT EXISTS events_test;
+use events_test;
+#
+# Events grants test begin
+#
+CREATE EVENT one_event ON SCHEDULE EVERY 10 SECOND DO SELECT 123;
+--replace_column 8 # 9 #
+SHOW EVENTS;
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
+CREATE DATABASE events_test2;
+CREATE USER ev_test@localhost;
+GRANT ALL ON events_test.* to ev_test@localhost;
+GRANT ALL ON events_test2.* to ev_test@localhost;
+REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
+#now we are on con1
+connect (ev_con1,localhost,ev_test,,events_test2);
+select "NEW CONNECTION";
+SELECT USER(), DATABASE();
+SHOW GRANTS;
+--echo "Here comes an error:";
+#NO EVENT_ACL on events_test2
+--error 1044
+SHOW EVENTS;
+USE events_test;
+--echo "We should see one event";
+--replace_column 8 # 9 #
+SHOW EVENTS;
+#now create an event with the same name but we are different user
+SELECT CONCAT("Let's create some new events from the name of ", USER());
+--error ER_EVENT_ALREADY_EXISTS
+CREATE EVENT one_event ON SCHEDULE EVERY 20 SECOND DO SELECT 123;
+CREATE EVENT two_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION NOT PRESERVE COMMENT "two event" DO SELECT 123;
+CREATE EVENT three_event ON SCHEDULE EVERY 20 SECOND ON COMPLETION PRESERVE COMMENT "three event" DO SELECT 123;
+
+--echo "Now we should see 3 events:";
+--replace_column 8 # 9 #
+SHOW EVENTS;
+
+--echo "This should show us only 2 events:";
+--replace_column 8 # 9 #
+SHOW EVENTS LIKE 't%event';
+
+--echo "This should show us no events:";
+--replace_column 8 # 9 #
+SHOW EVENTS FROM test LIKE '%';
+#ok, we are back
+connection default;
+GRANT EVENT ON events_test2.* TO ev_test@localhost;
+connection ev_con1;
+USE events_test2;
+CREATE EVENT four_event ON SCHEDULE EVERY 20 SECOND DO SELECT 42;
+connection default;
+USE events_test;
+--echo "We should see 4 events : one_event, two_event, three_event & four_event"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+DROP DATABASE events_test2;
+--echo "We should see 3 events : one_event, two_event, three_event"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+
+connection default;
+CREATE DATABASE events_test2;
+USE events_test2;
+CREATE EVENT five_event ON SCHEDULE EVERY 20 SECOND DO SELECT 42;
+
+connection ev_con1;
+--echo "Should see 4 events - one, two, three & five"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+connection default;
+REVOKE EVENT ON events_test2.* FROM ev_test@localhost;
+connection ev_con1;
+USE test;
+--echo "Should see 3 events - one, two & three"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+--echo "Let's test ALTER EVENT which changes the definer"
+USE events_test;
+ALTER EVENT one_event ON SCHEDULE EVERY 10 SECOND;
+--echo "The definer should be ev_test@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+connection default;
+USE events_test;
+ALTER EVENT one_event COMMENT "comment";
+connection ev_con1;
+--echo "The definer should be root@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+ALTER EVENT one_event DO SELECT 12;
+--echo "The definer should be ev_test@localhost"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='one_event';
+connection default;
+--echo "make the definer again root@localhost"
+ALTER EVENT one_event COMMENT "new comment";
+connection ev_con1;
+--echo "test DROP by another user"
+DROP EVENT one_event;
+connection default;
+--echo "One event should not be there"
+SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS;
+disconnect ev_con1;
+connection default;
+DROP USER ev_test@localhost;
+DROP DATABASE events_test2;
+#
+## EVENTS grants test end
+#
+
+DROP DATABASE events_test;
diff --git a/mysql-test/t/events_logs_tests.test b/mysql-test/t/events_logs_tests.test
index 21adc17d5b8..6d3b3292630 100644
--- a/mysql-test/t/events_logs_tests.test
+++ b/mysql-test/t/events_logs_tests.test
@@ -10,19 +10,21 @@ BEGIN
END|
delimiter ;|
--echo "Check General Query Log"
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
TRUNCATE mysql.general_log;
--echo "1 row, the current statement!"
+--replace_column 1 USER_HOST
call select_general_log();
SET GLOBAL event_scheduler=1;
--echo "Wait the scheduler to start"
--echo "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
--sleep 2
+--replace_column 1 USER_HOST
call select_general_log();
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
-SET GLOBAL event_scheduler=0;
+SET GLOBAL event_scheduler=2;
--sleep 1
--echo "Check slow query log"
@@ -50,13 +52,14 @@ SET @old_session_long_query_time:=@@long_query_time;
SHOW VARIABLES LIKE 'log_slow_queries';
DROP FUNCTION get_value;
TRUNCATE mysql.slow_log;
+--replace_column 1 USER_HOST
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "Set new values"
SET GLOBAL long_query_time=4;
-SET SESSION long_query_time=2;
+SET SESSION long_query_time=1;
--echo "Check that logging is working"
-SELECT SLEEP(3);
---replace_regex /00:00:0[3-5]/SLEEPVAL/
+SELECT SLEEP(2);
+--replace_column 1 USER_HOST 2 SLEEPVAL
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
@@ -73,14 +76,15 @@ SELECT * FROM slow_event_test;
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "This should go to the slow log"
SET SESSION long_query_time=10;
+SET GLOBAL long_query_time=1;
DROP EVENT long_event;
-CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5);
+CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
--echo "Sleep some more time than the actual event run will take"
---sleep 7
+--sleep 3
--echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
---echo "Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
---replace_regex /00:00:0[5-7]/SLEEPVAL/
+--echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
+--replace_column 1 USER_HOST 2 SLEEPVAL
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time;
diff --git a/mysql-test/t/events_microsec.test b/mysql-test/t/events_microsec.test
index 34855fdadff..e01120a0756 100644
--- a/mysql-test/t/events_microsec.test
+++ b/mysql-test/t/events_microsec.test
@@ -1,55 +1,15 @@
create database if not exists events_test;
use events_test;
---error 1235
+--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 MICROSECOND DO SELECT 1;
---error 1235
+--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 DAY_MICROSECOND DO SELECT 1;
---error 1235
+--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 HOUR_MICROSECOND DO SELECT 1;
---error 1235
+--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 MINUTE_MICROSECOND DO SELECT 1;
---error 1235
+--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 SECOND_MICROSECOND DO SELECT 1;
---echo "Now create normal event and change it on SQL level"
-CREATE EVENT micro_test2 ON SCHEDULE EVERY 1 MONTH DO SELECT 1;
-UPDATE mysql.event SET interval_field='MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
---error 1235
-SHOW CREATE EVENT micro_test2;
-SET GLOBAL event_scheduler=0;
---sleep 1
---echo "Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-UPDATE mysql.event SET interval_field='DAY_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
---error 1235
-SHOW CREATE EVENT micro_test2;
-SET GLOBAL event_scheduler=0;
---sleep 1
---echo "Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-UPDATE mysql.event SET interval_field='SECOND_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
---error 1235
-SHOW CREATE EVENT micro_test2;
-SET GLOBAL event_scheduler=0;
---sleep 1
---echo "Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-UPDATE mysql.event SET interval_field='HOUR_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
---error 1235
-SHOW CREATE EVENT micro_test2;
-SET GLOBAL event_scheduler=0;
---sleep 1
---echo "Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-UPDATE mysql.event SET interval_field='MINUTE_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
---error 1235
-SHOW CREATE EVENT micro_test2;
-SET GLOBAL event_scheduler=0;
---sleep 1
---echo "Should not be running:"
-SHOW VARIABLES like 'event_scheduler';
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='event_scheduler';
-DROP EVENT micro_test2;
-
drop database events_test;
diff --git a/mysql-test/t/events_scheduling.test b/mysql-test/t/events_scheduling.test
index ae3cc7d5fac..c688864a1e6 100644
--- a/mysql-test/t/events_scheduling.test
+++ b/mysql-test/t/events_scheduling.test
@@ -6,7 +6,9 @@ CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1;
-CREATE EVENT E19170 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
+# We need to have 2 to make it safe with valgrind. This is probably because
+# of when we calculate the timestamp value
+CREATE EVENT E19170 ON SCHEDULE EVERY 2 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND
@@ -15,7 +17,7 @@ CREATE EVENT start_n_end
DO INSERT INTO table_2 VALUES(1);
--sleep 5
CREATE EVENT only_one_time ON SCHEDULE EVERY 2 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_3 VALUES(1);
-CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_4 VALUES(1);
+CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND ON COMPLETION PRESERVE DO INSERT INTO table_4 VALUES(1);
--sleep 5
SELECT IF(SUM(a) >= 4, 'OK', 'ERROR') FROM table_1;
SELECT IF(SUM(a) >= 5, 'OK', 'ERROR') FROM table_2;
@@ -28,8 +30,8 @@ DROP EVENT start_n_end;
--echo "Already dropped because ended. Therefore an error."
--error ER_EVENT_DOES_NOT_EXIST
DROP EVENT only_one_time;
---echo "Already dropped because ended. Therefore an error."
---error ER_EVENT_DOES_NOT_EXIST
+--echo "Should be preserved"
+SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
DROP EVENT two_time;
DROP TABLE table_1;
DROP TABLE table_2;
diff --git a/mysql-test/t/events_stress.test b/mysql-test/t/events_stress.test
index f6eed79425c..8d0034c232e 100644
--- a/mysql-test/t/events_stress.test
+++ b/mysql-test/t/events_stress.test
@@ -2,78 +2,124 @@ CREATE DATABASE IF NOT EXISTS events_test;
#
# DROP DATABASE test start (bug #16406)
#
-CREATE DATABASE events_test2;
-USE events_test2;
+CREATE DATABASE events_conn1_test2;
+CREATE TABLE events_test.fill_it(test_name varchar(20), occur datetime);
+CREATE USER event_user2@localhost;
+CREATE DATABASE events_conn2_db;
+GRANT ALL ON *.* TO event_user2@localhost;
+CREATE USER event_user3@localhost;
+CREATE DATABASE events_conn3_db;
+GRANT ALL ON *.* TO event_user3@localhost;
+connect (conn2,localhost,event_user2,,events_conn2_db);
+--echo "In the second connection we create some events which won't be dropped till the end"
+--disable_query_log
+let $1= 50;
+while ($1)
+{
+ eval CREATE EVENT conn2_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn2_ev$1", NOW());
+ dec $1;
+}
+--enable_query_log
+connect (conn3,localhost,event_user3,,events_conn3_db);
+--echo "In the second connection we create some events which won't be dropped till the end"
+--disable_query_log
+let $1= 50;
+while ($1)
+{
+ eval CREATE EVENT conn3_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn3_ev$1", NOW());
+ dec $1;
+}
+--enable_query_log
+connection default;
+USE events_conn1_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
-DROP DATABASE events_test2;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
+DROP DATABASE events_conn1_test2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--echo "Now testing stability - dropping db -> events while they are running"
-CREATE DATABASE events_test2;
-USE events_test2;
+CREATE DATABASE events_conn1_test2;
+USE events_conn1_test2;
--disable_query_log
-let $1= 1000;
+let $1= 50;
while ($1)
{
- eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
+ eval CREATE EVENT conn1_round1_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round1_ev$1", NOW());
dec $1;
}
--enable_query_log
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
SET GLOBAL event_scheduler=1;
---sleep 4
-DROP DATABASE events_test2;
+--sleep 6
+DROP DATABASE events_conn1_test2;
-SET GLOBAL event_scheduler=0;
---sleep 2
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
-CREATE DATABASE events_test3;
-USE events_test3;
+SET GLOBAL event_scheduler=2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
+CREATE DATABASE events_conn1_test3;
+USE events_conn1_test3;
--disable_query_log
-let $1= 950;
+let $1= 50;
while ($1)
{
- eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
+ eval CREATE EVENT conn1_round2_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round2_ev$1", NOW());
dec $1;
}
--enable_query_log
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
---sleep 3
-CREATE DATABASE events_test4;
-USE events_test4;
+SET GLOBAL event_scheduler=1;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
+CREATE DATABASE events_conn1_test4;
+USE events_conn1_test4;
--disable_query_log
-let $1= 860;
+let $1= 50;
while ($1)
{
- eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
+ eval CREATE EVENT conn1_round3_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round3_ev$1", NOW());
dec $1;
}
--enable_query_log
-
-CREATE DATABASE events_test2;
-USE events_test2;
+CREATE DATABASE events_conn1_test2;
+USE events_conn1_test2;
--disable_query_log
-let $1= 1050;
+let $1= 50;
while ($1)
{
- eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
+ eval CREATE EVENT ev_round4_drop$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round4_ev$1", NOW());
dec $1;
}
--enable_query_log
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--sleep 6
-DROP DATABASE events_test2;
-SET GLOBAL event_scheduler=0;
-DROP DATABASE events_test3;
-SET GLOBAL event_scheduler=1;
-DROP DATABASE events_test4;
+connection conn2;
+--send
+DROP DATABASE events_conn2_db;
+connection conn3;
+--send
+DROP DATABASE events_conn3_db;
+connection default;
+--send
+DROP DATABASE events_conn1_test2;
+DROP DATABASE events_conn1_test3;
+SET GLOBAL event_scheduler=2;
+DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
+connection conn2;
+reap;
+disconnect conn2;
+connection conn3;
+reap;
+disconnect conn3;
+connection default;
USE events_test;
+DROP TABLE fill_it;
+--disable_query_log
+DROP USER event_user2@localhost;
+DROP USER event_user3@localhost;
+--enable_query_log
#
# DROP DATABASE test end (bug #16406)
#
diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test
index a38771db233..efce0cdf3b5 100644
--- a/mysql-test/t/explain.test
+++ b/mysql-test/t/explain.test
@@ -15,9 +15,9 @@ explain select * from t1 ignore key (str) where str="foo";
explain select * from t1 use key (str,str) where str="foo";
#The following should give errors
---error 1072
+--error 1176
explain select * from t1 use key (str,str,foo) where str="foo";
---error 1072
+--error 1176
explain select * from t1 ignore key (str,str,foo) where str="foo";
drop table t1;
diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test
index 3c43fb1d1f9..f6799f3630a 100644
--- a/mysql-test/t/federated.test
+++ b/mysql-test/t/federated.test
@@ -1,6 +1,6 @@
# should work with embedded server after mysqltest is fixed
--- source include/not_embedded.inc
-source include/federated.inc;
+--source include/not_embedded.inc
+--source include/federated.inc
connection slave;
DROP TABLE IF EXISTS federated.t1;
@@ -1310,6 +1310,57 @@ select * from federated.t1 where fld_parentid=0 and fld_delt=0;
DROP TABLE federated.t1;
connection slave;
DROP TABLE federated.bug_17377_table;
+DROP TABLE federated.t1;
+
+#
+# Test multi updates and deletes without keys
+#
+
+# The following can be enabled when bug #19773 has been fixed
+--disable_parsing
+connection slave;
+create table federated.t1 (i1 int, i2 int, i3 int);
+create table federated.t2 (id int, c1 varchar(20), c2 varchar(20));
+connection master;
+eval create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+eval create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2';
+insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from federated.t1 order by i1;
+select * from federated.t2;
+update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from federated.t1 order by i1;
+select * from federated.t2 order by id;
+delete t1.*,t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
+select * from federated.t1 order by i1;
+select * from federated.t2 order by id;
+drop table federated.t1, federated.t2;
+connection slave;
+drop table federated.t1, federated.t2;
+connection master;
+# Test multi updates and deletes with keys
+
+connection slave;
+create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1));
+create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id));
+connection master;
+eval create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+eval create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2';
+insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from federated.t1 order by i1;
+select * from federated.t2 order by id;
+update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from federated.t1 order by i1;
+select * from federated.t2 order by id;
+delete t1.*,t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
+select * from federated.t1 order by i1;
+select * from federated.t2 order by id;
+drop table federated.t1, federated.t2;
+connection slave;
+drop table federated.t1, federated.t2;
+connection master;
+--enable_parsing
-source include/federated_cleanup.inc;
+--source include/federated_cleanup.inc
diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test
index f5fd9fcadf2..95ba633fefd 100644
--- a/mysql-test/t/flush.test
+++ b/mysql-test/t/flush.test
@@ -102,3 +102,43 @@ unlock tables;
drop table t1, t2, t3;
# End of 4.1 tests
+
+#
+# Test of deadlock problem when doing FLUSH TABLE with read lock
+# (Bug was in NTPL threads in Linux when using different mutex while
+# waiting for a condtion variable)
+
+create table t1 (c1 int);
+create table t2 (c1 int);
+
+connect (con1,localhost,root,,);
+connect (con3,localhost,root,,);
+
+connection con1;
+lock table t1 write;
+
+connection con2;
+send flush tables with read lock;
+--sleep 1
+
+connection con3;
+send insert into t2 values(1);
+--sleep 1
+
+connection con1;
+unlock tables;
+disconnect con1;
+
+connection con2;
+reap;
+disconnect con2;
+
+connection con3;
+# It hangs here (insert into t2 does not end).
+reap;
+disconnect con3;
+
+connection default;
+drop table t1, t2;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index fbfdfa3b5d0..7fd7edddf28 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -176,8 +176,8 @@ select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5)
select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1 group by 1;
# The following returns random results as we are sorting on blob addresses
-# select group_concat(c order by (select group_concat(c order by a) from t2 where t2.a=t1.a)) as grp from t1;
-# select group_concat(c order by (select group_concat(c) from t2 where a=t1.a)) as grp from t1;
+select group_concat(c order by (select concat(5-t1.c,group_concat(c order by a)) from t2 where t2.a=t1.a)) as grp from t1;
+select group_concat(c order by (select concat(t1.c,group_concat(c)) from t2 where a=t1.a)) as grp from t1;
select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp;
drop table t1,t2;
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 17f5d3a6b3d..eacc4fc6710 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -546,7 +546,6 @@ DROP TABLE t1;
# Bug #12882 min/max inconsistent on empty table
#
# Test case moved to func_group_innodb
-
# End of 4.1 tests
#
diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test
index 351d1fc2c92..8ddf1fbe314 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -220,3 +220,15 @@ set @str=NULL;
drop table t2;
drop table t1;
+# BUG#19618: Crash in range optimizer for
+# "unsigned_keypart NOT IN(negative_number,...)"
+# (introduced in fix BUG#15872)
+create table t1 (
+ some_id smallint(5) unsigned,
+ key (some_id)
+);
+insert into t1 values (1),(2);
+select some_id from t1 where some_id not in(2,-1);
+select some_id from t1 where some_id not in(-4,-1,-4);
+select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
+drop table t1;
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index dee06231deb..7f809dbc4a1 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -698,4 +698,10 @@ select cast(rtrim(' 20.06 ') as decimal(19,2));
select cast(ltrim(' 20.06 ') as decimal(19,2));
select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2));
+#
+# Bug #13975: "same string" + 0 has 2 different results
+#
+select conv("18383815659218730760",10,10) + 0;
+select "18383815659218730760" + 0;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 5c993028cb4..e6c1ddfcf1f 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -385,6 +385,7 @@ select time_format('100:00:00', '%H %k %h %I %l');
create table t1 (a timestamp default '2005-05-05 01:01:01',
b timestamp default '2005-05-05 01:01:01');
delimiter //;
+drop function if exists t_slow_sysdate;
create function t_slow_sysdate() returns timestamp
begin
do sleep(2);
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 97f13381557..a9d52f559ca 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -302,7 +302,7 @@ DROP DATABASE testdb10;
create table t1(a int, b int, c int, d int);
grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost;
show grants for grant_user@localhost;
-select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv;
+select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name;
revoke ALL PRIVILEGES on t1 from grant_user@localhost;
show grants for grant_user@localhost;
select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv;
@@ -326,7 +326,18 @@ grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost;
grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost;
connect (conn1,localhost,mysqltest_3,,);
connection conn1;
-show grants for mysqltest_3@localhost;
+SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES
+ WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE;
+SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
+ WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ ORDER BY TABLE_NAME,PRIVILEGE_TYPE;
+SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES
+ WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE;
+SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES
+ WHERE GRANTEE = '''mysqltest_3''@''localhost'''
+ ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE;
--error 1143
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
--error 1143
@@ -479,6 +490,7 @@ insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_gr
flush privileges;
delete from tables_priv where host = '' and user = 'mysqltest_1';
flush privileges;
+use test;
#
# Bug #10892 user variables not auto cast for comparisons
@@ -507,7 +519,6 @@ create user mysqltest_7@;
set password for mysqltest_7@ = password('systpass');
show grants for mysqltest_7@;
drop user mysqltest_7@;
-flush privileges; # BUG#16297(flush should be removed when that bug is fixed)
--error 1141
show grants for mysqltest_7@;
@@ -528,3 +539,145 @@ flush privileges;
drop database mysqltest;
# End of 4.1 tests
+
+#
+# Bug #16297 In memory grant tables not flushed when users's hostname is ""
+#
+use test;
+create table t1 (a int);
+
+# Backup anonymous users and remove them. (They get in the way of
+# the one we test with here otherwise.)
+create table t2 as select * from mysql.user where user='';
+delete from mysql.user where user='';
+flush privileges;
+
+# Create some users with different hostnames
+create user mysqltest_8@'';
+create user mysqltest_8;
+create user mysqltest_8@host8;
+
+# Try to create them again
+--error 1396
+create user mysqltest_8@'';
+--error 1396
+create user mysqltest_8;
+--error 1396
+create user mysqltest_8@host8;
+
+select user, QUOTE(host) from mysql.user where user="mysqltest_8";
+
+--echo Schema privileges
+grant select on mysqltest.* to mysqltest_8@'';
+show grants for mysqltest_8@'';
+grant select on mysqltest.* to mysqltest_8@;
+show grants for mysqltest_8@;
+grant select on mysqltest.* to mysqltest_8;
+show grants for mysqltest_8;
+select * from information_schema.schema_privileges
+where grantee like "'mysqltest_8'%";
+connect (conn3,localhost,mysqltest_8,,);
+select * from t1;
+disconnect conn3;
+connection master;
+revoke select on mysqltest.* from mysqltest_8@'';
+revoke select on mysqltest.* from mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.schema_privileges
+where grantee like "'mysqltest_8'%";
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8@;
+grant select on mysqltest.* to mysqltest_8@'';
+flush privileges;
+show grants for mysqltest_8@;
+revoke select on mysqltest.* from mysqltest_8@'';
+flush privileges;
+
+--echo Column privileges
+grant update (a) on t1 to mysqltest_8@'';
+grant update (a) on t1 to mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.column_privileges;
+connect (conn4,localhost,mysqltest_8,,);
+select * from t1;
+disconnect conn4;
+connection master;
+revoke update (a) on t1 from mysqltest_8@'';
+revoke update (a) on t1 from mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.column_privileges;
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+
+--echo Table privileges
+grant update on t1 to mysqltest_8@'';
+grant update on t1 to mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.table_privileges;
+connect (conn5,localhost,mysqltest_8,,);
+select * from t1;
+disconnect conn5;
+connection master;
+revoke update on t1 from mysqltest_8@'';
+revoke update on t1 from mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.table_privileges;
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+
+--echo "DROP USER" should clear privileges
+grant all privileges on mysqltest.* to mysqltest_8@'';
+grant select on mysqltest.* to mysqltest_8@'';
+grant update on t1 to mysqltest_8@'';
+grant update (a) on t1 to mysqltest_8@'';
+grant all privileges on mysqltest.* to mysqltest_8;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.user_privileges
+where grantee like "'mysqltest_8'%";
+connect (conn5,localhost,mysqltest_8,,);
+select * from t1;
+disconnect conn5;
+connection master;
+flush privileges;
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+drop user mysqltest_8@'';
+--error 1141
+show grants for mysqltest_8@'';
+show grants for mysqltest_8;
+select * from information_schema.user_privileges
+where grantee like "'mysqltest_8'%";
+drop user mysqltest_8;
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error 1045
+connect (conn6,localhost,mysqltest_8,,);
+connection master;
+--error 1141
+show grants for mysqltest_8;
+drop user mysqltest_8@host8;
+--error 1141
+show grants for mysqltest_8@host8;
+
+# Restore the anonymous users.
+insert into mysql.user select * from t2;
+flush privileges;
+drop table t2;
+
+drop table t1;
+
+
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
index df2f567626b..292b5cde77f 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -665,9 +665,6 @@ select distinct a1 from t1 where a2 = 'b';
# Test case moved to group_min_max_innodb
-
-drop table t1,t2,t3;
-
#
# Bug #6142: a problem with the empty innodb table
#
diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test
index 82294db336d..e501fce1eeb 100644
--- a/mysql-test/t/heap.test
+++ b/mysql-test/t/heap.test
@@ -458,4 +458,16 @@ create table t2 (c varchar(10)) engine=memory;
show table status like 't_';
drop table t1, t2;
+#
+# BUG#18233 - Memory tables INDEX USING HASH (a,b) returns 1 row on
+# SELECT WHERE a= AND b=
+#
+CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256),
+ KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256));
+SELECT COUNT(*) FROM t1 WHERE a='a';
+SELECT COUNT(*) FROM t1 WHERE b='aa';
+SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256);
+DROP TABLE t1;
+
# End of 5.0 tests
diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test
index f1b9d290885..fb715fccefe 100644
--- a/mysql-test/t/heap_btree.test
+++ b/mysql-test/t/heap_btree.test
@@ -176,4 +176,12 @@ UPDATE t1 SET val=1;
SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1';
DROP TABLE t1;
+#
+# BUG#12873 - BTREE index on MEMORY table with multiple NULL values doesn't
+# work properly
+#
+CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES(NULL),(NULL);
+DROP TABLE t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/im_cmd_line.imtest b/mysql-test/t/im_cmd_line.imtest
new file mode 100644
index 00000000000..00e8351535e
--- /dev/null
+++ b/mysql-test/t/im_cmd_line.imtest
@@ -0,0 +1,68 @@
+###########################################################################
+#
+# Tests for user-management command-line options.
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+
+# List users so we are sure about starting conditions.
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Add a new user.
+
+--echo ==> Adding user 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --add-user --username=testuser --password=abc 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Printing out line for 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=abc | tail -1
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Edit user's attributes.
+
+--echo ==> Changing the password of 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --edit-user --username=testuser --password=xyz 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Printing out line for 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=xyz | tail -1
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Drop user.
+
+--echo ==> Dropping user 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --drop-user --username=testuser 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
diff --git a/mysql-test/t/im_daemon_life_cycle-im.opt b/mysql-test/t/im_daemon_life_cycle-im.opt
index 21c01191e4c..3a45c7a41f7 100644
--- a/mysql-test/t/im_daemon_life_cycle-im.opt
+++ b/mysql-test/t/im_daemon_life_cycle-im.opt
@@ -1,2 +1,3 @@
--run-as-service
--log=$MYSQLTEST_VARDIR/log/im.log
+--monitoring-interval=1
diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest
index 87388d7c1e6..d173ce2a6e2 100644
--- a/mysql-test/t/im_daemon_life_cycle.imtest
+++ b/mysql-test/t/im_daemon_life_cycle.imtest
@@ -10,6 +10,9 @@
###########################################################################
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
SHOW INSTANCES;
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted
diff --git a/mysql-test/t/im_instance_conf-im.opt b/mysql-test/t/im_instance_conf-im.opt
new file mode 100644
index 00000000000..34b74ce0c95
--- /dev/null
+++ b/mysql-test/t/im_instance_conf-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_instance_conf.imtest b/mysql-test/t/im_instance_conf.imtest
new file mode 100644
index 00000000000..17703fdd303
--- /dev/null
+++ b/mysql-test/t/im_instance_conf.imtest
@@ -0,0 +1,228 @@
+###########################################################################
+#
+# This test suite checks the following statements:
+# - CREATE INSTANCE <instance_name> [option1[=option1_value], ...];
+# - DROP INSTANCE <instance_name>;
+#
+# For CREATE INSTANCE we check that:
+# - CREATE INSTANCE succeeds for non-existing instance;
+# - CREATE INSTANCE fails for existing instance;
+# - CREATE INSTANCE can get additional options with and w/o values;
+# - CREATE INSTANCE parses options and handles grammar errors correctly.
+# Check that strings with spaces are handled correctly, unknown (for
+# mysqld) options should also be handled;
+# - CREATE INSTANCE updates both config file and internal configuration cache;
+# - CREATE INSTANCE allows to create instances only with properly formed
+# names (mysqld*);
+#
+# For DROP INSTANCE we check that:
+# - DROP INSTANCE succeeds for existing instance;
+# - DROP INSTANCE fails for non-existing instance;
+# - DROP INSTANCE fails for active instance.
+# - DROP INSTANCE updates both config file and internal configuration cache;
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+#
+# Check starting conditions.
+#
+###########################################################################
+
+# Check that the configuration file contains only instances that we expect.
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# Check that mysqld1 is reported as running.
+
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
+SHOW INSTANCES;
+
+# Check that the expected mysqld instance is actually run (check that we can
+# connect and execute something).
+
+--echo
+--echo ---> connection: mysql1_con
+--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--disconnect mysql1_con
+
+--echo
+--echo ---> connection: default
+--connection default
+
+###########################################################################
+#
+# CREATE INSTANCE tests.
+#
+###########################################################################
+
+# Check that CREATE INSTANCE succeeds for non-existing instance and also check
+# that both config file and internal configuration cache have been updated.
+
+CREATE INSTANCE mysqld3;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+# Check that CREATE INSTANCE fails for existing instance. Let's all three
+# existing instances (running one, stopped one and just created one). Just in
+# case...
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld1;
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld2;
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld3;
+
+# Check that CREATE INSTANCE can get additional options with and w/o values.
+# Ensure that config file is updated properly.
+
+# - without values;
+
+--echo --------------------------------------------------------------------
+--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld4 nonguarded;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# - with value;
+
+--echo --------------------------------------------------------------------
+--exec grep test-A $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-B $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-A $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-B $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# Check that CREATE INSTANCE parses options and handles grammar errors
+# correctly. Check that strings with spaces are handled correctly,
+# unknown (for mysqld) options should also be handled.
+
+# - check handling of extra spaces;
+
+--echo --------------------------------------------------------------------
+--exec grep test-C $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld6 test-C1 = 10 , test-C2 = 02 ;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-C1 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-C2 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# - check handling of grammar error;
+
+--echo --------------------------------------------------------------------
+--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld7 test-D = test-D-value ;
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld8 test-E 0 ;
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld8 test-F = ;
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+# - check parsing of string option values
+
+--echo --------------------------------------------------------------------
+--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld9 test-1=" hello world ", test-2=' ';
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
+# test-3='abc def'
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
+# test-6=abc
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld10 test-bad=' \ ';
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-5 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-6 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-7 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-bad $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+
+# Check that CREATE INSTANCE allows to create instances only with properly
+# formed names (mysqld*).
+
+--error 3014 # ER_MALFORMED_INSTANCE_NAME
+CREATE INSTANCE qqq1;
+
diff --git a/mysql-test/t/im_life_cycle-im.opt b/mysql-test/t/im_life_cycle-im.opt
new file mode 100644
index 00000000000..34b74ce0c95
--- /dev/null
+++ b/mysql-test/t/im_life_cycle-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_life_cycle.imtest b/mysql-test/t/im_life_cycle.imtest
index 246843a022b..d71cdc86624 100644
--- a/mysql-test/t/im_life_cycle.imtest
+++ b/mysql-test/t/im_life_cycle.imtest
@@ -17,11 +17,15 @@
#
###########################################################################
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.1.
+--echo --------------------------------------------------------------------
+
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
SHOW INSTANCES;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld1;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld2;
###########################################################################
#
@@ -33,20 +37,22 @@ SHOW INSTANCE STATUS mysqld2;
#
###########################################################################
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.2.
+--echo --------------------------------------------------------------------
+
START INSTANCE mysqld2;
-# FIXME
+# FIXME: START INSTANCE should be synchronous.
--sleep 3
+# should be longer than monitoring interval and enough to start instance.
SHOW INSTANCES;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld1;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld2;
---connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+--connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD2_PORT,$IM_MYSQLD2_SOCK)
--connection mysql_con
---replace_result $IM_MYSQLD1_PORT IM_MYSQLD1_PORT
+--replace_result $IM_MYSQLD2_PORT IM_MYSQLD2_PORT
SHOW VARIABLES LIKE 'port';
--connection default
@@ -61,9 +67,15 @@ SHOW VARIABLES LIKE 'port';
#
###########################################################################
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.3.
+--echo --------------------------------------------------------------------
+
STOP INSTANCE mysqld2;
-# FIXME
+# FIXME: STOP INSTANCE should be synchronous.
--sleep 3
+# should be longer than monitoring interval and enough to stop instance.
SHOW INSTANCES;
--replace_column 3 VERSION_NUMBER 4 VERSION
@@ -81,16 +93,17 @@ SHOW INSTANCE STATUS mysqld2;
#
###########################################################################
---error 3000
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.4.
+--echo --------------------------------------------------------------------
+
+--error 3000 # ER_BAD_INSTANCE_NAME
START INSTANCE mysqld3;
---error 3002
+--error 3002 # ER_INSTANCE_ALREADY_STARTED
START INSTANCE mysqld1;
-# FIXME TODO
-# BUG#12813: START/STOP INSTANCE commands accept a list as argument
-# START INSTANCE mysqld1, mysqld2;
-
###########################################################################
#
# 1.1.5. Check that Instance Manager reports correct errors for 'STOP INSTANCE'
@@ -101,39 +114,54 @@ START INSTANCE mysqld1;
#
###########################################################################
---error 3000
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.5.
+--echo --------------------------------------------------------------------
+
+--error 3000 # ER_BAD_INSTANCE_NAME
STOP INSTANCE mysqld3;
# TODO: IM should be fixed.
# BUG#12673: Instance Manager allows to stop the instance many times
-# --error 3002
+# --error 3002 # ER_INSTANCE_ALREADY_STARTED
# STOP INSTANCE mysqld2;
-# FIXME TODO
-# BUG#12813: START/STOP INSTANCE commands accept a list as argument
-# STOP INSTANCE mysqld1, mysqld2;
-
###########################################################################
#
# 1.1.6. Check that Instance Manager is able to restart guarded instances.
#
###########################################################################
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.6.
+--echo --------------------------------------------------------------------
+
SHOW INSTANCES;
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
###########################################################################
#
# 1.1.7. Check that Instance Manager does not restart non-guarded instance.
#
###########################################################################
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.7.
+--echo --------------------------------------------------------------------
+
SHOW INSTANCES;
START INSTANCE mysqld2;
-# FIXME
+# FIXME: START INSTANCE should be synchronous.
--sleep 3
+# should be longer than monitoring interval and enough to start instance.
SHOW INSTANCES;
@@ -147,7 +175,13 @@ SHOW INSTANCES;
# incomplete SHOW INSTANCE STATUS command.
#
###########################################################################
---error 1149
+
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.8.
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
SHOW INSTANCE STATUS;
#
@@ -159,8 +193,13 @@ SHOW INSTANCE STATUS;
# a list as argument.
#
---error 1149
+--echo
+--echo --------------------------------------------------------------------
+--echo -- BUG#12813
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
START INSTANCE mysqld1,mysqld2,mysqld3;
---error 1149
+--error ER_SYNTAX_ERROR
STOP INSTANCE mysqld1,mysqld2,mysqld3;
diff --git a/mysql-test/t/im_options.imtest b/mysql-test/t/im_options.imtest
new file mode 100644
index 00000000000..cd905416cda
--- /dev/null
+++ b/mysql-test/t/im_options.imtest
@@ -0,0 +1,268 @@
+###########################################################################
+#
+# This test suite checks the following statements:
+# - SET <instance id>.<option name> = <option value>;
+# - UNSET <instance id>.<option name> = <option value>;
+# - FLUSH INSTANCES;
+#
+# For SET/UNSET we check that:
+# - SET ignores spaces correctly;
+# - UNSET does not allow option-value part (= <option value>);
+# - SET/UNSET can be applied several times w/o error;
+# - SET/UNSET is allowed only for stopped instances;
+# - SET/UNSET updates both the configuration cache in IM and
+# the configuration file;
+#
+# For FLUSH INSTANCES we check that:
+# - FLUSH INSTANCES is allowed only when all instances are stopped;
+#
+# According to the IM implementation details, we should play at least with the
+# following options:
+# - server_id
+# - port
+# - nonguarded
+
+# Let's test SET statement on the option 'server_id'. It's expected that
+# originally the instances have the following server ids and states:
+# - mysqld1: server_id: 1; running (online)
+# - mysqld2: server_id: 2; stopped (offline)
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+#
+# Check starting conditions.
+#
+###########################################################################
+
+# - check the configuration file;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+# - check the running instances.
+
+--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--connection default
+
+# - check the internal cache.
+
+SHOW INSTANCES;
+
+###########################################################################
+#
+# Check that SET/UNSET is allowed only for stopped instances.
+#
+###########################################################################
+
+# - check that SET/UNSET is denied for running instances;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld1.server_id;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld1.server_id = 11;
+
+# - check that SET/UNSET is denied for active instances:
+# - create dummy misconfigured instance;
+# - start it;
+# - try to set/unset options;
+
+CREATE INSTANCE mysqld3 datadir = '/';
+START INSTANCE mysqld3;
+
+# FIXME: START INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
+# NOTE: We can not analyze state of the instance here -- it can be Failed or
+# Starting because Instance Manager is trying to start the misconfigured
+# instance several times.
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld3.server_id;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld3.server_id = 11;
+
+STOP INSTANCE mysqld3;
+
+# FIXME: STOP INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to stop instance.
+
+--replace_column 3 VERSION_NUMBER 4 VERSION
+SHOW INSTANCE STATUS mysqld3;
+
+# - check that SET/UNSET succeed for stopped instances;
+# - check that SET/UNSET can be applied multiple times;
+
+UNSET mysqld2.server_id;
+UNSET mysqld2.server_id;
+
+--replace_column 2 option_value
+SHOW INSTANCE OPTIONS mysqld2;
+
+SET mysqld2.server_id = 2;
+SET mysqld2.server_id = 2;
+
+--replace_column 2 option_value
+SHOW INSTANCE OPTIONS mysqld2;
+
+# - check that UNSET does not allow option-value part (= <option value>);
+
+--error ER_SYNTAX_ERROR
+UNSET mysqld2.server_id = 11;
+
+# - check that SET/UNSET working properly with multiple options;
+
+SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep ddd $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ddd $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+# - check that if some instance name is invalid or the active is active,
+# whole SET-statement will not be executed;
+
+--error 3000 # ER_BAD_INSTANCE_NAME
+SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+# - check that if some instance name is invalid or the active is active,
+# whole UNSET-statement will not be executed;
+
+--error 3000 # ER_BAD_INSTANCE_NAME
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+DROP INSTANCE mysqld3;
+
+# - check that spaces are handled correctly;
+
+SET mysqld2.server_id=222;
+SET mysqld2.server_id = 222;
+SET mysqld2.server_id = 222 ;
+SET mysqld2 . server_id = 222 ;
+SET mysqld2 . server_id = 222 , mysqld2 . aaa , mysqld2 . bbb ;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+UNSET mysqld2 . aaa , mysqld2 . bbb ;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+###########################################################################
+#
+# Check that SET/UNSET updates both the configuration cache in IM and
+# the configuration file.
+#
+###########################################################################
+
+# - check that the configuration file has been updated (i.e. contains
+# server_id=SERVER_ID for mysqld2);
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+# - (for mysqld1) check that the running instance has not been affected:
+# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
+# returns zero;
+
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--connection default
+
+# - check that internal cache of Instance Manager has been affected;
+# TODO: we should check only server_id option here.
+
+# SHOW INSTANCE OPTIONS mysqld2;
+
+###########################################################################
+#
+# Check that FLUSH INSTANCES is allowed only when all instances are stopped.
+#
+###########################################################################
+
+SHOW INSTANCES;
+
+--error 3016 # ER_THERE_IS_ACTIVE_INSTACE
+FLUSH INSTANCES;
+
+STOP INSTANCE mysqld1;
+# FIXME: STOP INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to stop instance.
+
+SHOW INSTANCES;
+
+FLUSH INSTANCES;
diff --git a/mysql-test/t/im_options_set.imtest b/mysql-test/t/im_options_set.imtest
deleted file mode 100644
index a9b64861f99..00000000000
--- a/mysql-test/t/im_options_set.imtest
+++ /dev/null
@@ -1,142 +0,0 @@
-###########################################################################
-#
-# This file contains test for (3) test suite.
-#
-# Consult WL#2789 for more information.
-#
-###########################################################################
-
-#
-# Check the options-management commands:
-# - SET;
-# - FLUSH INSTANCES;
-#
-# Let's test the commands on the option 'server_id'. It's expected that
-# originally the instances have the following server ids:
-# - mysqld1: 1
-# - mysqld2: 2
-#
-# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
-# 1.1. check that the configuration file has been updated (i.e. contains
-# server_id=SERVER_ID for the instance);
-# 1.2. (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns zero;
-# 1.3. check that internal cache of Instance Manager has not been affected
-# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-#
-# 2. FLUSH INSTANCES;
-# 2.1. check that the configuration file has not been updated;
-# 2.2. (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns zero value;
-# 2.3. check that internal cache of Instance Manager has been updated (i.e.
-# SHOW INSTANCE OPTIONS <instance> contains 'server_id=SERVER_ID' line).
-#
-# 3. Restore options.
-#
-
-###########################################################################
-
---source include/im_check_os.inc
-
-###########################################################################
-#
-# 0. Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
-#
-###########################################################################
-
-# * mysqld1
-
-SET mysqld1.server_id = 11;
-
-# - check that the configuration file has been updated (i.e. contains
-# server_id=SERVER_ID for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns zero;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check that internal cache of Instance Manager has not been affected
-# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-
-# * mysqld2
-
-SET mysqld2.server_id = 12;
-
-# - check that the configuration file has been updated (i.e. contains
-# server_id=SERVER_ID for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check that internal cache of Instance Manager has not been affected
-# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 2. FLUSH INSTANCES;
-#
-###########################################################################
-
-FLUSH INSTANCES;
-
-# - check that the configuration file has not been updated;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns zero value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check that internal cache of Instance Manager has been updated (i.e.
-# SHOW INSTANCE OPTIONS <instance> contains 'server_id=' line).
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
diff --git a/mysql-test/t/im_options_unset.imtest b/mysql-test/t/im_options_unset.imtest
deleted file mode 100644
index 40629805d45..00000000000
--- a/mysql-test/t/im_options_unset.imtest
+++ /dev/null
@@ -1,150 +0,0 @@
-###########################################################################
-#
-# This file contains test for (3) test suite.
-#
-# Consult WL#2789 for more information.
-#
-###########################################################################
-
-#
-# Check the options-management commands:
-# - UNSET;
-# - FLUSH INSTANCES;
-#
-# Let's test the commands on the option 'server_id'. It's expected that
-# originally the instances have the following server ids:
-# - mysqld1: 1
-# - mysqld2: 2
-#
-# The test case:
-#
-# 1. UNSET <instance_id>.server_id;
-#
-# Do the step for both instances.
-#
-# 1.1. check that the configuration file has been updated (i.e. does not
-# contain 'server_id=' line for the instance);
-# 1.2. (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns non-zero value;
-# 1.3. check that internal cache of Instance Manager is not affected (i.e.
-# SHOW INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-#
-# 2. FLUSH INSTANCES;
-#
-# Do the step for both instances.
-#
-# 2.1. check that the configuration file has not been updated (i.e. does not
-# contain 'server_id=' for the instance);
-# 2.2. (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns non-zero value;
-# 2.3. check that internal cache of Instance Manager has been updated (i.e.
-# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
-#
-
-###########################################################################
-
---source include/im_check_os.inc
-
-###########################################################################
-#
-# 0. Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 1. UNSET <instance_id>.server_id;
-#
-###########################################################################
-
-# * mysqld1
-
-UNSET mysqld1.server_id;
-
-# - check that the configuration file has been updated (i.e. does not
-# contain 'server_id=' line for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check that the running instance has not been affected: connect to the
-# instance and check that 'SHOW VARIABLES LIKE 'server_id'' returns non-zero
-# value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check that internal cache of Instance Manager is not affected (i.e. SHOW
-# INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-
-# * mysqld2
-
-UNSET mysqld2.server_id;
-
-# - check that the configuration file has been updated (i.e. does not
-# contain 'server_id=' line for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
-
-# - check that internal cache of Instance Manager is not affected (i.e. SHOW
-# INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 2. FLUSH INSTANCES;
-#
-###########################################################################
-
-FLUSH INSTANCES;
-
-# - check that the configuration file has not been updated (i.e. does not
-# contain 'server_id=' for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
-
-# - (for mysqld1) check that the running instance has not been affected:
-# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-# returns non-zero value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check that internal cache of Instance Manager has been updated (i.e.
-# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
-# TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
diff --git a/mysql-test/t/im_utils-im.opt b/mysql-test/t/im_utils-im.opt
new file mode 100644
index 00000000000..34b74ce0c95
--- /dev/null
+++ b/mysql-test/t/im_utils-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_utils.imtest b/mysql-test/t/im_utils.imtest
index dc6fb93c4ff..8e8d475cfee 100644
--- a/mysql-test/t/im_utils.imtest
+++ b/mysql-test/t/im_utils.imtest
@@ -17,6 +17,9 @@
# - the second instance is offline;
#
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
SHOW INSTANCES;
#
@@ -41,8 +44,9 @@ SHOW INSTANCE OPTIONS mysqld2;
START INSTANCE mysqld2;
-# FIXME
--- sleep 3
+# FIXME: START INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
STOP INSTANCE mysqld2;
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 274b4eae71f..acb877e1e74 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -5,9 +5,6 @@
# on the presence of the log tables (which are CSV-based).
--source include/have_csv.inc
-# This test uses chmod, can't be run with root permissions
--- source include/not_as_root.inc
-
# Test for information_schema.schemata &
# show databases
@@ -846,4 +843,22 @@ select user,db from information_schema.processlist;
connection default;
drop user user3148@localhost;
+#
+# Bug#16681 information_schema shows forbidden VIEW details
+#
+grant select on test.* to mysqltest_1@localhost;
+create table t1 (id int);
+create view v1 as select * from t1;
+create definer = mysqltest_1@localhost
+sql security definer view v2 as select 1;
+
+connect (con16681,localhost,mysqltest_1,,test);
+connection con16681;
+
+select * from information_schema.views
+where table_name='v1' or table_name='v2';
+connection default;
+drop view v1, v2;
+drop table t1;
+drop user mysqltest_1@localhost;
diff --git a/mysql-test/t/information_schema_chmod.test b/mysql-test/t/information_schema_chmod.test
index fb850b8e38d..c7ea2b03890 100644
--- a/mysql-test/t/information_schema_chmod.test
+++ b/mysql-test/t/information_schema_chmod.test
@@ -8,6 +8,9 @@
#
--source include/not_windows.inc
+# This test uses chmod, can't be run with root permissions
+-- source include/not_as_root.inc
+
#
# Bug #15851 Unlistable directories yield no info from information_schema
diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test
index b65135a621d..2cfa766d799 100644
--- a/mysql-test/t/information_schema_db.test
+++ b/mysql-test/t/information_schema_db.test
@@ -1,16 +1,25 @@
-- source include/testdb_only.inc
+--disable_warnings
+drop table if exists t1,t2;
+drop view if exists v1,v2;
+drop function if exists f1;
+drop function if exists f2;
+--enable_warnings
+
use INFORMATION_SCHEMA;
--replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema
show tables;
--replace_result 'Tables_in_INFORMATION_SCHEMA (T%)' 'Tables_in_information_schema (T%)'
show tables from INFORMATION_SCHEMA like 'T%';
create database `inf%`;
+create database mbase;
use `inf%`;
show tables;
#
# Bug#18113 SELECT * FROM information_schema.xxx crashes server
+# Bug#17204 second CALL to procedure crashes Server
# Crash happened when one selected data from one of INFORMATION_SCHEMA
# tables and in order to build its contents server had to open view which
# used stored function and table or view on which one had not global or
@@ -18,6 +27,7 @@ show tables;
# privileges at all).
#
grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost';
+grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost';
create table t1 (f1 int);
delimiter |;
create function func1(curr_int int) returns int
@@ -28,15 +38,63 @@ begin
end|
delimiter ;|
create view v1 as select f1 from t1 where f1 = func1(f1);
+create function func2() returns int return 1;
+
+use mbase;
+delimiter |;
+create procedure p1 ()
+begin
+select table_name from information_schema.key_column_usage
+order by table_name;
+end|
+delimiter ;|
+
+create table t1
+(f1 int(10) unsigned not null,
+ f2 varchar(100) not null,
+ primary key (f1), unique key (f2));
+
connect (user1,localhost,mysqltest_1,,);
connection user1;
--disable_result_log
select * from information_schema.tables;
+call mbase.p1();
+call mbase.p1();
+call mbase.p1();
--enable_result_log
+
connection default;
+use `inf%`;
drop user mysqltest_1@localhost;
+drop table t1;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='inf%' and func2();
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='inf%' and func2();
drop view v1;
drop function func1;
-drop table t1;
+drop function func2;
drop database `inf%`;
+drop procedure mbase.p1;
+drop database mbase;
+
+#
+# Bug#18282 INFORMATION_SCHEMA.TABLES provides inconsistent info about invalid views
+#
+use test;
+create table t1 (i int);
+create function f1 () returns int return (select max(i) from t1);
+create view v1 as select f1();
+create table t2 (id int);
+create function f2 () returns int return (select max(i) from t2);
+create view v2 as select f2();
+drop table t2;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='test';
+drop table t1;
+select table_name, table_type, table_comment from information_schema.tables
+where table_schema='test';
+drop function f1;
+drop function f2;
+drop view v1, v2;
diff --git a/mysql-test/t/information_schema_part.test b/mysql-test/t/information_schema_part.test
index 163b04248b8..4cbf21ca1d3 100644
--- a/mysql-test/t/information_schema_part.test
+++ b/mysql-test/t/information_schema_part.test
@@ -99,3 +99,25 @@ select * from information_schema.partitions where table_schema="test"
and table_name="t1";
drop table t1;
+#
+# Bug 20161 Partitions: SUBPARTITION METHOD doesn't show LINEAR keyword
+#
+create table t1 (a int)
+PARTITION BY RANGE (a)
+SUBPARTITION BY LINEAR HASH (a)
+(PARTITION p0 VALUES LESS THAN (10));
+
+SHOW CREATE TABLE t1;
+select SUBPARTITION_METHOD FROM information_schema.partitions WHERE
+table_schema="test" AND table_name="t1";
+drop table t1;
+
+create table t1 (a int)
+PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN
+(10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+ 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53));
+SHOW CREATE TABLE t1;
+SELECT PARTITION_DESCRIPTION FROM information_schema.partitions WHERE
+table_schema = "test" AND table_name = "t1";
+drop table t1;
diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test
index 0237913dfc9..bea2d3bc8e0 100644
--- a/mysql-test/t/innodb_mysql.test
+++ b/mysql-test/t/innodb_mysql.test
@@ -1,7 +1,7 @@
-- source include/have_innodb.inc
--disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t1m,t1i,t2m,t2i,t4;
--enable_warnings
# BUG#16798: Uninitialized row buffer reads in ref-or-null optimizer
@@ -58,6 +58,220 @@ where
drop table t1, t2;
+#
+# Bug #12882 min/max inconsistent on empty table
+#
+
+--disable_warnings
+create table t1m (a int) engine=myisam;
+create table t1i (a int) engine=innodb;
+create table t2m (a int) engine=myisam;
+create table t2i (a int) engine=innodb;
+--enable_warnings
+insert into t2m values (5);
+insert into t2i values (5);
+
+# test with MyISAM
+select min(a) from t1m;
+select min(7) from t1m;
+select min(7) from DUAL;
+explain select min(7) from t2m join t1m;
+select min(7) from t2m join t1m;
+
+select max(a) from t1m;
+select max(7) from t1m;
+select max(7) from DUAL;
+explain select max(7) from t2m join t1m;
+select max(7) from t2m join t1m;
+
+select 1, min(a) from t1m where a=99;
+select 1, min(a) from t1m where 1=99;
+select 1, min(1) from t1m where a=99;
+select 1, min(1) from t1m where 1=99;
+
+select 1, max(a) from t1m where a=99;
+select 1, max(a) from t1m where 1=99;
+select 1, max(1) from t1m where a=99;
+select 1, max(1) from t1m where 1=99;
+
+# test with InnoDB
+select min(a) from t1i;
+select min(7) from t1i;
+select min(7) from DUAL;
+explain select min(7) from t2i join t1i;
+select min(7) from t2i join t1i;
+
+select max(a) from t1i;
+select max(7) from t1i;
+select max(7) from DUAL;
+explain select max(7) from t2i join t1i;
+select max(7) from t2i join t1i;
+
+select 1, min(a) from t1i where a=99;
+select 1, min(a) from t1i where 1=99;
+select 1, min(1) from t1i where a=99;
+select 1, min(1) from t1i where 1=99;
+
+select 1, max(a) from t1i where a=99;
+select 1, max(a) from t1i where 1=99;
+select 1, max(1) from t1i where a=99;
+select 1, max(1) from t1i where 1=99;
+
+# mixed MyISAM/InnoDB test
+explain select count(*), min(7), max(7) from t1m, t1i;
+select count(*), min(7), max(7) from t1m, t1i;
+
+explain select count(*), min(7), max(7) from t1m, t2i;
+select count(*), min(7), max(7) from t1m, t2i;
+
+explain select count(*), min(7), max(7) from t2m, t1i;
+select count(*), min(7), max(7) from t2m, t1i;
+
+drop table t1m, t1i, t2m, t2i;
+
+#
+# Bug #12672: primary key implcitly included in every innodb index
+# (was part of group_min_max.test)
+#
+
+create table t1 (
+ a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+);
+
+insert into t1 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
+--disable_warnings
+create table t4 (
+ pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+) engine=innodb;
+--enable_warnings
+insert into t4 (a1, a2, b, c, d, dummy) select * from t1;
+
+create index idx12672_0 on t4 (a1);
+create index idx12672_1 on t4 (a1,a2,b,c);
+create index idx12672_2 on t4 (a1,a2,b);
+analyze table t1;
+
+select distinct a1 from t4 where pk_col not in (1,2,3,4);
+
+drop table t1,t4;
+
+#
+# Bug #6142: a problem with the empty innodb table
+# (was part of group_min_max.test)
+#
+
+--disable_warnings
+create table t1 (
+ a varchar(30), b varchar(30), primary key(a), key(b)
+) engine=innodb;
+--enable_warnings
+select distinct a from t1;
+drop table t1;
+
+#
+# Bug #9798: group by with rollup
+# (was part of group_min_max.test)
+#
+
+--disable_warnings
+create table t1(a int, key(a)) engine=innodb;
+--enable_warnings
+insert into t1 values(1);
+select a, count(a) from t1 group by a with rollup;
+drop table t1;
+
+#
+# Bug #13293 Wrongly used index results in endless loop.
+# (was part of group_min_max.test)
+#
+create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb;
+insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d");
+alter table t1 drop primary key, add primary key (f2, f1);
+explain select distinct f1 a, f1 b from t1;
+explain select distinct f1, f2 from t1;
+drop table t1;
+
+
+#
+# Test of behaviour with CREATE ... SELECT
+#
+
+set storage_engine=innodb;
+CREATE TABLE t1 (a int, b int);
+insert into t1 values (1,1),(1,2);
+--error 1062
+CREATE TABLE t2 (primary key (a)) select * from t1;
+# This should give warning
+drop table if exists t2;
+--error 1062
+CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1;
+# This should give warning
+drop table if exists t2;
+CREATE TABLE t2 (a int, b int, primary key (a));
+BEGIN;
+INSERT INTO t2 values(100,100);
+--error 1062
+CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+SELECT * from t2;
+ROLLBACK;
+SELECT * from t2;
+TRUNCATE table t2;
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * from t2;
+drop table t2;
+
+CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a));
+BEGIN;
+INSERT INTO t2 values(100,100);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+SELECT * from t2;
+COMMIT;
+BEGIN;
+INSERT INTO t2 values(101,101);
+--error 1062
+CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1;
+SELECT * from t2;
+ROLLBACK;
+SELECT * from t2;
+TRUNCATE table t2;
+--error 1062
+INSERT INTO t2 select * from t1;
+SELECT * from t2;
+drop table t1,t2;
#
# Bug#17530: Incorrect key truncation on table creation caused server crash.
diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test
index f3dd8e7e199..e2514083ea7 100644
--- a/mysql-test/t/insert.test
+++ b/mysql-test/t/insert.test
@@ -9,8 +9,8 @@ drop table if exists t1,t2,t3;
create table t1 (a int not null);
insert into t1 values (1);
insert into t1 values (a+2);
-insert into t1 values (a+3);
-insert into t1 values (4),(a+5);
+insert into t1 values (a+3),(a+4);
+insert into t1 values (5),(a+6);
select * from t1;
drop table t1;
@@ -176,3 +176,28 @@ insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 =
select count(*) from t2;
drop table t1,t2,t3;
+#
+# Test different cases of duplicate fields
+#
+
+create table t1 (a int, b int);
+insert into t1 (a,b) values (a,b);
+insert into t1 SET a=1, b=a+1;
+insert into t1 (a,b) select 1,2;
+INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a);
+prepare stmt1 from ' replace into t1 (a,a) select 100, ''hundred'' ';
+--error 1110
+execute stmt1;
+--error 1110
+insert into t1 (a,b,b) values (1,1,1);
+--error 1136
+insert into t1 (a,a) values (1,1,1);
+--error 1110
+insert into t1 (a,a) values (1,1);
+--error 1110
+insert into t1 SET a=1,b=2,a=1;
+--error 1110
+insert into t1 (b,b) select 1,2;
+--error 1110
+INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a);
+drop table t1;
diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test
index e8afa701a84..3f82219fadb 100644
--- a/mysql-test/t/join_outer.test
+++ b/mysql-test/t/join_outer.test
@@ -791,3 +791,21 @@ SELECT v1.a, v2. b
DROP VIEW v1,v2;
DROP TABLE t1,t2;
+
+#
+# Bug 19816: LEFT OUTER JOIN with constant ORed predicates in WHERE clause
+#
+
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (b int);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (2), (3);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1);
+
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1 OR 1);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (0 OR 1);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 2=2);
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 1=0);
+
+DROP TABLE t1,t2;
diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test
index fcd127e3e98..aff5efa51cb 100644
--- a/mysql-test/t/loaddata.test
+++ b/mysql-test/t/loaddata.test
@@ -92,6 +92,10 @@ load data infile '../std_data_ln/rpl_loaddata.dat' into table t1 (@a, @b);
select * from t1;
select @a, @b;
truncate table t1;
+# Reading of all columns with set
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t1 set c=b;
+select * from t1;
+truncate table t1;
# now going to test fixed field-row file format
load data infile '../std_data_ln/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c="Wow";
select * from t1;
diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test
index 3d07ec98d69..7fc65f52214 100644
--- a/mysql-test/t/lock_multi.test
+++ b/mysql-test/t/lock_multi.test
@@ -126,3 +126,68 @@ show columns from t1;
connection locker;
unlock tables;
drop table t1;
+
+#
+# Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock
+#
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+#
+connection con1;
+CREATE DATABASE mysqltest_1;
+FLUSH TABLES WITH READ LOCK;
+#
+# With bug in place: acquire LOCK_mysql_create_table and
+# wait in wait_if_global_read_lock().
+connection con2;
+send DROP DATABASE mysqltest_1;
+--sleep 1
+#
+# With bug in place: try to acquire LOCK_mysql_create_table...
+# When fixed: Reject dropping db because of the read lock.
+connection con1;
+--error ER_CANT_UPDATE_WITH_READLOCK
+DROP DATABASE mysqltest_1;
+UNLOCK TABLES;
+#
+connection con2;
+reap;
+#
+connection default;
+disconnect con1;
+disconnect con2;
+# This must have been dropped by connection 2 already,
+# which waited until the global read lock was released.
+--error ER_DB_DROP_EXISTS
+DROP DATABASE mysqltest_1;
+
+# Bug#16986 - Deadlock condition with MyISAM tables
+#
+connection locker;
+use mysql;
+LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE;
+FLUSH TABLES;
+--sleep 1
+#
+connection reader;
+use mysql;
+#NOTE: This must be a multi-table select, otherwise the deadlock will not occur
+send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1;
+--sleep 1
+#
+connection locker;
+# Make test case independent from earlier grants.
+--replace_result "Table is already up to date" "OK"
+OPTIMIZE TABLES columns_priv, db, host, user;
+UNLOCK TABLES;
+#
+connection reader;
+reap;
+use test;
+#
+connection locker;
+use test;
+#
+connection default;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test
index 048da802d02..5b79e5e4625 100644
--- a/mysql-test/t/log_tables.test
+++ b/mysql-test/t/log_tables.test
@@ -16,10 +16,10 @@ use mysql;
#
truncate table general_log;
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 2 USER_HOST 3 THREAD_ID
select * from general_log;
truncate table slow_log;
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 2 USER_HOST
select * from slow_log;
#
@@ -31,7 +31,7 @@ select * from slow_log;
#
truncate table general_log;
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 2 USER_HOST 3 THREAD_ID
select * from general_log where argument like '%general_log%';
@@ -47,6 +47,7 @@ insert into join_test values ("User performed a usual SQL query", "Query");
insert into join_test values ("New DB connection was registered", "Connect");
insert into join_test values ("Get the table info", "Field List");
+--replace_column 2 USER_HOST
select verbose_comment, user_host, argument
from mysql.general_log join join_test
on (mysql.general_log.command_type = join_test.command_type);
@@ -156,7 +157,7 @@ truncate table mysql.general_log;
set names utf8;
create table bug16905 (s char(15) character set utf8 default 'пуÑто');
insert into bug16905 values ('новое');
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 2 USER_HOST 3 THREAD_ID
select * from mysql.general_log;
drop table bug16905;
@@ -167,7 +168,7 @@ drop table bug16905;
truncate table mysql.slow_log;
set session long_query_time=1;
select sleep(2);
---replace_column 1 TIMESTAMP, 3 USER_HOST, 4 QUERY_TIME
+--replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME
select * from mysql.slow_log;
# kill all connections
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index acc816ae921..04c33e9d709 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -532,3 +532,33 @@ select * from t1;
select * from t2;
drop view v1;
drop table t1, t2;
+
+#
+# Test multi updates and deletes using primary key and without.
+#
+create table t1 (i1 int, i2 int, i3 int);
+create table t2 (id int, c1 varchar(20), c2 varchar(20));
+insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from t1 order by i1;
+select * from t2;
+update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from t1 order by i1;
+select * from t2 order by id;
+delete t1.*,t2.* from t1,t2 where t1.i2=t2.id;
+select * from t1 order by i1;
+select * from t2 order by id;
+drop table t1, t2;
+create table t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1));
+create table t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id));
+insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
+insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
+select * from t1 order by i1;
+select * from t2 order by id;
+update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
+select * from t1 order by i1;
+select * from t2 order by id;
+delete t1.*,t2.* from t1,t2 where t1.i2=t2.id;
+select * from t1 order by i1;
+select * from t2 order by id;
+drop table t1, t2;
diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test
index 1bede1d5c9a..ceba78bf762 100644
--- a/mysql-test/t/mysqlbinlog.test
+++ b/mysql-test/t/mysqlbinlog.test
@@ -124,9 +124,19 @@ select HEX(f) from t3;
select HEX(f) from t04;
select HEX(f) from t4;
+#
+#BUG#14157: utf8 encoding in binlog without set character_set_client
+#
+flush logs;
+--exec $MYSQL test -e 'create table if not exists t5 (a int); set names latin1; create temporary table `äöüÄÖÜ` (a int); insert into `äöüÄÖÜ` values (1); insert into t5 select * from `äöüÄÖÜ`'
+# resulted binlog, parly consisting of multi-byte utf8 chars,
+# must be digestable for both client and server. In 4.1 the client
+# should use default-character-set same as the server.
+--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000006 | $MYSQL
+select * from t5 /* must be (1),(1) */;
# clean up
-drop table t1, t2, t03, t04, t3, t4;
+drop table t1, t2, t03, t04, t3, t4, t5;
-# End of 4.1 tests
+# End of 5.0 tests
diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test
index 61d64c733d7..f5eddff8816 100644
--- a/mysql-test/t/mysqlcheck.test
+++ b/mysql-test/t/mysqlcheck.test
@@ -5,6 +5,10 @@
# depends on the presence of the log tables (which are CSV-based).
--source include/have_csv.inc
+--disable_warnings
+drop database if exists client_test_db;
+--enable_warnings
+
DROP SCHEMA test;
CREATE SCHEMA test;
#
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 732a3ce89da..98e881b67d5 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -2,7 +2,7 @@
--source include/not_embedded.inc
--disable_warnings
-DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
+DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa, t3;
drop database if exists mysqldump_test_db;
drop database if exists db1;
drop database if exists db2;
@@ -607,6 +607,13 @@ drop table t1, t2;
drop database db1;
#
+# BUG#15328 Segmentation fault occured if my.cnf is invalid for escape sequence
+#
+
+--exec $MYSQL_MY_PRINT_DEFAULTS --defaults-file=$MYSQL_TEST_DIR/std_data/bug15328.cnf mysqldump
+
+
+#
# Bug #9558 mysqldump --no-data db t1 t2 format still dumps data
#
@@ -741,6 +748,17 @@ show create table `t1`;
drop table `t1`;
+#
+# Bug #18536: wrong table order
+#
+
+create table t1(a int);
+create table t2(a int);
+create table t3(a int);
+--error 6
+--exec $MYSQL_DUMP --skip-comments --force --no-data test t3 t1 non_existing t2
+drop table t1, t2, t3;
+
--echo End of 4.1 tests
# Bug #13318: Bad result with empty field and --hex-blob
#
diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test
index 29deea4aa0d..8e3b4a6ca89 100644
--- a/mysql-test/t/ndb_alter_table.test
+++ b/mysql-test/t/ndb_alter_table.test
@@ -3,7 +3,7 @@
-- source include/not_embedded.inc
--disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
drop database if exists mysqltest;
--enable_warnings
@@ -383,3 +383,18 @@ LOAD DATA INFILE 'tmp.dat' INTO TABLE ndb_show_tables;
select 'no_copy' from ndb_show_tables where id = @t1_id and name like '%t1%';
DROP TABLE t1, ndb_show_tables;
+
+# simple test that auto incr is not lost at rename or alter
+create table t1 (a int primary key auto_increment, b int) engine=ndb;
+insert into t1 (b) values (101),(102),(103);
+select * from t1 where a = 3;
+alter table t1 rename t2;
+insert into t2 (b) values (201),(202),(203);
+select * from t2 where a = 6;
+alter table t2 add c int;
+insert into t2 (b) values (301),(302),(303);
+select * from t2 where a = 9;
+alter table t2 rename t1;
+insert into t1 (b) values (401),(402),(403);
+select * from t1 where a = 12;
+drop table t1;
diff --git a/mysql-test/t/ndb_autodiscover3.test b/mysql-test/t/ndb_autodiscover3.test
index afbebc4dd03..ed75c89cdd1 100644
--- a/mysql-test/t/ndb_autodiscover3.test
+++ b/mysql-test/t/ndb_autodiscover3.test
@@ -43,6 +43,7 @@ select * from t2 order by a limit 3;
--error ER_NO_SUCH_TABLE
select * from t2;
show tables like 't2';
+reset master;
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from t2 order by a limit 3;
@@ -50,6 +51,7 @@ select * from t2 order by a limit 3;
# server 1 should have a stale cache, and in this case wrong frm, transaction must be retried
--connection server1
select * from t2 order by a limit 3;
+reset master;
--exec $NDB_MGM --no-defaults -e "all restart -i" >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults >> $NDB_TOOLS_OUTPUT
@@ -60,6 +62,7 @@ select * from t2 order by a limit 3;
--error ER_NO_SUCH_TABLE
select * from t2;
show tables like 't2';
+reset master;
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from t2 order by a limit 3;
@@ -67,6 +70,7 @@ select * from t2 order by a limit 3;
# server 2 should have a stale cache, but with right frm, transaction need not be retried
--connection server2
select * from t2 order by a limit 3;
+reset master;
drop table t2;
# End of 4.1 tests
diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test
index d11e30ae97d..c7fa5aeee1e 100644
--- a/mysql-test/t/ndb_basic.test
+++ b/mysql-test/t/ndb_basic.test
@@ -713,3 +713,17 @@ select * from t1 order by f1;
select * from t1 order by f2;
select * from t1 order by f3;
drop table t1;
+
+#
+# Bug #18483 Cannot create table with FK constraint
+# ndb does not support foreign key constraint, it is silently ignored
+# in line with other storage engines
+#
+CREATE TABLE t1 (a VARCHAR(255) NOT NULL,
+ CONSTRAINT pk_a PRIMARY KEY (a))engine=ndb;
+CREATE TABLE t2(a VARCHAR(255) NOT NULL,
+ b VARCHAR(255) NOT NULL,
+ c VARCHAR(255) NOT NULL,
+ CONSTRAINT pk_b_c_id PRIMARY KEY (b,c),
+ CONSTRAINT fk_a FOREIGN KEY(a) REFERENCES t1(a))engine=ndb;
+drop table t1, t2;
diff --git a/mysql-test/t/ndb_blob.test b/mysql-test/t/ndb_blob.test
index bf82a793049..d6e0edc89f0 100644
--- a/mysql-test/t/ndb_blob.test
+++ b/mysql-test/t/ndb_blob.test
@@ -428,4 +428,60 @@ truncate t1;
select count(*) from t1;
drop table t1;
+# -- bug#19956 - var* key, complex key
+
+create table t1 (
+ a varchar(40) not null,
+ b mediumint not null,
+ t text,
+ c varchar(2) not null,
+ d bigint not null,
+ primary key (a,b,c),
+ key (c,a),
+ unique key (d)
+) engine=ndb;
+
+--disable_query_log
+set @s1 = 'rggurloniukyehuxdbfkkyzlceixzrehqhvxvxbpwizzvjzpucqmzrhzxzfau';
+set @s2 = 'ykyymbzqgqlcjhlhmyqelfoaaohvtbekvifukdtnvcrrjveevfakxarxexomz';
+set @s3 = 'dbnfqyzgtqxalcrwtfsqabknvtfcbpoonxsjiqvmhnfikxxhcgoexlkoezvah';
+set @v1 = repeat(@s1,123);
+set @v2 = repeat(@s2,234);
+set @v3 = repeat(@s3,345);
+set @v4 = NULL;
+--enable_query_log
+
+insert into t1 (a,b,c,d,t) values ('a',1110,'a',1,@v1);
+insert into t1 (a,b,c,d,t) values ('b',1110,'a',2,@v2);
+insert into t1 (a,b,c,d,t) values ('a',1110,'b',3,@v3);
+insert into t1 (a,b,c,d,t) values ('b',1110,'b',4,@v4);
+select a,b,c,d,sha1(t) from t1 order by c,a;
+
+select a,b,c,d,sha1(t) from t1 where a='a' and b=1110 and c='a';
+select a,b,c,d,sha1(t) from t1 where a='a' and b=1110 and c='b';
+
+update t1 set t=@v4 where a='b' and b=1110 and c='a';
+update t1 set t=@v2 where a='b' and b=1110 and c='b';
+select a,b,c,d,sha1(t) from t1 order by c,a;
+
+update t1 set t=@v2 where d=2;
+update t1 set t=@v4 where d=4;
+select a,b,c,d,sha1(t) from t1 order by c,a;
+
+update t1 set t=@v4 where a='b' and c='a';
+update t1 set t=@v2 where a='b' and c='b';
+select a,b,c,d,sha1(t) from t1 order by c,a;
+
+update t1 set t=@v2 where b+d=1112;
+update t1 set t=@v4 where b+d=1114;
+select a,b,c,d,sha1(t) from t1 order by c,a;
+
+delete from t1 where a='a' and b=1110 and c='a';
+delete from t1 where a='b' and c='a';
+delete from t1 where d=3;
+delete from t1 where b+d=1114;
+select count(*) from t1;
+
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/ndb_dd_backuprestore.test b/mysql-test/t/ndb_dd_backuprestore.test
index be6d73e27b4..1508cccb46d 100644
--- a/mysql-test/t/ndb_dd_backuprestore.test
+++ b/mysql-test/t/ndb_dd_backuprestore.test
@@ -159,185 +159,15 @@ DROP TABLE test.t1;
DROP TABLE test.t2;
DROP TABLE test.t3;
DROP TABLE test.t4;
-###################### Adding partition #################################
--- echo **** Test 3 Adding partition Test backup and restore ****
-
-CREATE TABLESPACE table_space2
-ADD DATAFILE './table_space2/datafile.dat'
-USE LOGFILE GROUP log_group1
-INITIAL_SIZE 12M
-ENGINE NDB;
-
-CREATE TABLE test.t1 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(150) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space1 STORAGE DISK ENGINE=NDB PARTITION BY HASH(c3) PARTITIONS 4;
-
-CREATE TABLE test.t4 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(180) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY HASH(c3) PARTITIONS 2;
-
-CREATE TABLE test.t2 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space2 STORAGE DISK ENGINE=NDB PARTITION BY KEY(c3) (PARTITION p0 ENGINE = NDB, PARTITION p1 ENGINE = NDB);
-
-CREATE TABLE test.t5 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY KEY(pk1) (PARTITION p0 ENGINE = NDB, PARTITION p1 ENGINE = NDB);
-
-CREATE TABLE test.t3 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(202) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))TABLESPACE table_space2 STORAGE DISK ENGINE=NDB PARTITION BY RANGE (c3) PARTITIONS 3 (PARTITION x1 VALUES LESS THAN (105), PARTITION x2 VALUES LESS THAN (333), PARTITION x3 VALUES LESS THAN (720));
-
-CREATE TABLE test.t6 (pk1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 VARCHAR(220) NOT NULL, c3 INT NOT NULL, c4 BIT NOT NULL, PRIMARY KEY(pk1,c3))ENGINE=NDB PARTITION BY RANGE (pk1) PARTITIONS 2 (PARTITION x1 VALUES LESS THAN (333), PARTITION x2 VALUES LESS THAN (720));
-
-SHOW CREATE TABLE test.t1;
-
-SHOW CREATE TABLE test.t2;
-
-SHOW CREATE TABLE test.t3;
-
-SHOW CREATE TABLE test.t4;
-
-SHOW CREATE TABLE test.t5;
-
-SHOW CREATE TABLE test.t6;
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't1';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't2';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't3';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't4';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't5';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't6';
-
-
-let $j= 500;
---disable_query_log
-while ($j)
-{
- eval INSERT INTO test.t1 VALUES (NULL, "Sweden, Texas", $j, b'0');
- eval INSERT INTO test.t4 VALUES (NULL, "Sweden, Texas", $j, b'0');
- dec $j;
- eval INSERT INTO test.t2 VALUES (NULL, "Sweden, Texas, ITALY, Kyle, JO, JBM,TU", $j, b'1');
- eval INSERT INTO test.t5 VALUES (NULL, "Sweden, Texas, ITALY, Kyle, JO, JBM,TU", $j, b'1');
- dec $j;
- eval INSERT INTO test.t3 VALUES (NULL, "TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU", $j, b'1');
- eval INSERT INTO test.t6 VALUES (NULL, "TEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXASTEXAS, ITALY, Kyle, JO, JBM,TU", $j, b'1'); } --enable_query_log
-
-SELECT COUNT(*) FROM test.t1;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t1 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t2;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t2 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t3;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t3 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t4;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t4 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t5;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t5 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t6;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t6 ORDER BY c3 LIMIT 5;
-
--- source include/ndb_backup.inc
-
-DROP TABLE test.t1;
-DROP TABLE test.t2;
-DROP TABLE test.t3;
-DROP TABLE test.t4;
-DROP TABLE test.t5;
-DROP TABLE test.t6;
ALTER TABLESPACE table_space1
DROP DATAFILE './table_space1/datafile.dat'
ENGINE = NDB;
-ALTER TABLESPACE table_space2
-DROP DATAFILE './table_space2/datafile.dat'
-ENGINE = NDB;
-
DROP TABLESPACE table_space1
ENGINE = NDB;
-DROP TABLESPACE table_space2
-ENGINE = NDB;
-
DROP LOGFILE GROUP log_group1
ENGINE =NDB;
--- source include/ndb_restore_master.inc
-
-
-SHOW CREATE TABLE test.t1;
-
-SHOW CREATE TABLE test.t2;
-
-SHOW CREATE TABLE test.t3;
-
-SHOW CREATE TABLE test.t4;
-
-SHOW CREATE TABLE test.t5;
-
-SHOW CREATE TABLE test.t6;
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't1';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't2';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't3';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't4';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't5';
-
-SELECT * FROM information_schema.partitions WHERE table_name= 't6';
-
-SELECT COUNT(*) FROM test.t1;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t1 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t2;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t2 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t3;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t3 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t4;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t4 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t5;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t5 ORDER BY c3 LIMIT 5;
-
-SELECT COUNT(*) FROM test.t6;
-
-SELECT pk1, c2, c3, hex(c4) FROM test.t6 ORDER BY c3 LIMIT 5;
-
-# Cleanup
-
-DROP TABLE test.t1;
-DROP TABLE test.t2;
-DROP TABLE test.t3;
-DROP TABLE test.t4;
-DROP TABLE test.t5;
-DROP TABLE test.t6;
-
-ALTER TABLESPACE table_space1 DROP DATAFILE './table_space1/datafile.dat' ENGINE=NDB;
-
-ALTER TABLESPACE table_space2 DROP DATAFILE './table_space2/datafile.dat' ENGINE=NDB;
-
-DROP TABLESPACE table_space1 ENGINE = NDB;
-
-DROP TABLESPACE table_space2 ENGINE = NDB;
-
-DROP LOGFILE GROUP log_group1 ENGINE = NDB;
-
#End 5.1 test case
-
-
diff --git a/mysql-test/t/ndb_rename.test b/mysql-test/t/ndb_rename.test
new file mode 100644
index 00000000000..7f9fd0e6984
--- /dev/null
+++ b/mysql-test/t/ndb_rename.test
@@ -0,0 +1,36 @@
+-- source include/have_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+drop database if exists mysqltest;
+--enable_warnings
+
+#
+# Table rename tests
+#
+
+#
+# Create a normal table with primary key
+#
+CREATE TABLE t1 (
+ pk1 INT NOT NULL PRIMARY KEY,
+ attr1 INT NOT NULL,
+ attr2 INT,
+ attr3 VARCHAR(10),
+ INDEX i1(attr1)
+) ENGINE=ndbcluster;
+
+INSERT INTO t1 VALUES (0,0,0,"zero"),(1,1,1,"one"),(2,2,2,"two");
+SELECT * FROM t1 WHERE attr1 = 1;
+alter table t1 rename t2;
+SELECT * FROM t2 WHERE attr1 = 1;
+
+create database ndbtest;
+alter table t2 rename ndbtest.t2;
+SELECT * FROM ndbtest.t2 WHERE attr1 = 1;
+
+drop table ndbtest.t2;
+drop database ndbtest;
+
+# End of 4.1 tests
diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test
index 37001a27812..90cd27ded55 100644
--- a/mysql-test/t/partition.test
+++ b/mysql-test/t/partition.test
@@ -15,6 +15,19 @@ partition by key(a)
drop table t1;
#
+# BUG 19067 ALTER TABLE .. ADD PARTITION for subpartitioned table crashes
+#
+create table t1 (a int)
+partition by range (a)
+subpartition by key (a)
+(partition p0 values less than (1));
+alter table t1 add partition (partition p1 values less than (2));
+show create table t1;
+alter table t1 reorganize partition p1 into (partition p1 values less than (3));
+show create table t1;
+drop table t1;
+
+#
# Partition by key no partition defined => OK
#
CREATE TABLE t1 (
@@ -1018,6 +1031,14 @@ create index inx1 on t1(a);
drop table t1;
#
+# BUG 19304 Partitions: MERGE handler not allowed in partitioned tables
+#
+--error ER_PARTITION_MERGE_ERROR
+create table t1 (a int)
+partition by key (a)
+(partition p0 engine = MERGE);
+
+#
# BUG 19062 Partition clause ignored if CREATE TABLE ... AS SELECT ...;
#
create table t1 (a varchar(1))
@@ -1050,4 +1071,34 @@ ALTER TABLE t1 DISABLE KEYS;
ALTER TABLE t1 ENABLE KEYS;
DROP TABLE t1;
+#
+# Bug 17455 Partitions: Wrong message and error when using Repair/Optimize
+# table on partitioned table
+#
+create table t1 (a int)
+engine=MEMORY
+partition by key (a);
+
+REPAIR TABLE t1;
+OPTIMIZE TABLE t1;
+
+drop table t1;
+
+#
+# Bug 17310 Partitions: Bugs with archived partitioned tables
+#
+create database db99;
+use db99;
+create table t1 (a int not null)
+engine=archive
+partition by list (a)
+(partition p0 values in (1), partition p1 values in (2));
+insert into t1 values (1), (2);
+--error 0, 1005
+create index inx on t1 (a);
+alter table t1 add partition (partition p2 values in (3));
+alter table t1 drop partition p2;
+use test;
+drop database db99;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test
index 03a2ab41807..659f0b8cef4 100644
--- a/mysql-test/t/partition_error.test
+++ b/mysql-test/t/partition_error.test
@@ -747,3 +747,31 @@ CREATE TABLE t1(a int)
--error ER_NO_PARTITION_FOR_GIVEN_VALUE
insert into t1 values (10);
drop table t1;
+
+#
+# Bug 18198 Partitions: Verify that erroneus partition functions doesn't work
+#
+create table t1 (v varchar(12))
+partition by range (ascii(v))
+(partition p0 values less than (10));
+drop table t1;
+
+-- error 1064
+create table t1 (a int)
+partition by hash (rand(a));
+-- error 1064
+create table t1 (a int)
+partition by hash(CURTIME() + a);
+-- error 1064
+create table t1 (a int)
+partition by hash (NOW()+a);
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (a int)
+partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00')));
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (a int)
+partition by range (a + (select count(*) from t1))
+(partition p1 values less than (1));
+-- error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+create table t1 (a char(10))
+partition by hash (extractvalue(a,'a'));
diff --git a/mysql-test/t/partition_mgm_err2.test b/mysql-test/t/partition_mgm_err2.test
index dd96731ccdd..7d15bd7b19f 100644
--- a/mysql-test/t/partition_mgm_err2.test
+++ b/mysql-test/t/partition_mgm_err2.test
@@ -15,7 +15,7 @@ enable_query_log;
--system mkdir $MYSQLTEST_VARDIR/tmp/bug14354
disable_query_log;
eval CREATE TABLE t1 (id int) PARTITION BY RANGE(id) (
-PARTITION p1 VALUES LESS THAN (20) ENGINE=myiasm
+PARTITION p1 VALUES LESS THAN (20) ENGINE=myisam
DATA DIRECTORY="$MYSQLTEST_VARDIR/tmp/bug14354"
INDEX DIRECTORY="$MYSQLTEST_VARDIR/tmp/bug14354");
enable_query_log;
diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test
index 0c922392d32..976466e1578 100644
--- a/mysql-test/t/partition_pruning.test
+++ b/mysql-test/t/partition_pruning.test
@@ -556,7 +556,7 @@ drop table t1;
# being fixed.
#
-#BUG 17946 Like searches fail with partitioning
+# BUG#17946 Like searches fail with partitioning
#
create table t1 (a char(32) primary key)
partition by key()
@@ -566,3 +566,27 @@ select * from t1;
select * from t1 where a like 'n%';
drop table t1;
+
+# BUG#19055 Crashes for varchar_col=NUMBER or varchar_col IS NULL
+create table t1 (s1 varchar(15)) partition by key (s1);
+select * from t1 where s1 = 0 or s1 is null;
+insert into t1 values ('aa'),('bb'),('0');
+explain partitions select * from t1 where s1 = 0 or s1 is null;
+drop table t1;
+
+#
+# BUG#19684: EXPLAIN PARTITIONS produces garbage in 'partitions' column when
+# the length of string to be displayed exceeds some limit.
+create table t2 (a int, b int)
+ partition by LIST(a)
+ subpartition by HASH(b) subpartitions 40
+( partition p_0_long_partition_name values in(1),
+ partition p_1_long_partition_name values in(2));
+
+insert into t2 values (1,1),(2,2);
+
+--vertical_results
+explain partitions select * from t2;
+--horizontal_results
+drop table t2;
+
diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test
index f61a7820afe..0b9a46ad4d3 100644
--- a/mysql-test/t/ps_1general.test
+++ b/mysql-test/t/ps_1general.test
@@ -321,13 +321,15 @@ execute stmt4;
prepare stmt4 from ' show variables like ''sql_mode'' ';
execute stmt4;
prepare stmt4 from ' show engine bdb logs ';
-# The output depends on the history (actions of the bdb engine).
+# The output depends on the bdb being enabled and on the history
+# history (actions of the bdb engine).
# That is the reason why, we switch the output here off.
# (The real output will be tested in ps_6bdb.test)
-# --replace_result $MYSQL_TEST_DIR TEST_DIR
+--disable_warnings
--disable_result_log
execute stmt4;
--enable_result_log
+--enable_warnings
prepare stmt4 from ' show grants for user ';
--error 1295
prepare stmt4 from ' show create table t2 ';
diff --git a/mysql-test/t/rpl_ndb_2innodb-master.opt b/mysql-test/t/rpl_ndb_2innodb-master.opt
index f31d53c3cb1..701dddb075b 100644
--- a/mysql-test/t/rpl_ndb_2innodb-master.opt
+++ b/mysql-test/t/rpl_ndb_2innodb-master.opt
@@ -1 +1 @@
---default-storage-engine=ndb --binlog-format=row
+--default-storage-engine=ndbcluster
diff --git a/mysql-test/t/rpl_ndb_2innodb-slave.opt b/mysql-test/t/rpl_ndb_2innodb-slave.opt
index ee81186c513..d8857e54be2 100644
--- a/mysql-test/t/rpl_ndb_2innodb-slave.opt
+++ b/mysql-test/t/rpl_ndb_2innodb-slave.opt
@@ -1 +1 @@
---innodb --default-storage-engine=innodb --binlog-format=row
+--innodb --default-storage-engine=innodb
diff --git a/mysql-test/t/rpl_ndb_2myisam-master.opt b/mysql-test/t/rpl_ndb_2myisam-master.opt
index f31d53c3cb1..701dddb075b 100644
--- a/mysql-test/t/rpl_ndb_2myisam-master.opt
+++ b/mysql-test/t/rpl_ndb_2myisam-master.opt
@@ -1 +1 @@
---default-storage-engine=ndb --binlog-format=row
+--default-storage-engine=ndbcluster
diff --git a/mysql-test/t/rpl_ndb_2myisam-slave.opt b/mysql-test/t/rpl_ndb_2myisam-slave.opt
index 59de63c0da2..6035ce27c46 100644
--- a/mysql-test/t/rpl_ndb_2myisam-slave.opt
+++ b/mysql-test/t/rpl_ndb_2myisam-slave.opt
@@ -1 +1 @@
---default-storage-engine=myisam --binlog-format=row
+--default-storage-engine=myisam
diff --git a/mysql-test/t/rpl_ndb_dd_partitions.test b/mysql-test/t/rpl_ndb_dd_partitions.test
deleted file mode 100644
index 9291f38e8db..00000000000
--- a/mysql-test/t/rpl_ndb_dd_partitions.test
+++ /dev/null
@@ -1,310 +0,0 @@
-#######################################
-# Author: JBM #
-# Date: 2006-03-09 #
-# Purpose: To test the replication of #
-# Cluster Disk Data using partitions #
-#######################################
-
---source include/have_ndb.inc
---source include/have_binlog_format_row.inc
---source include/master-slave.inc
-
---echo --- Doing pre test cleanup ---
-
-connection master;
---disable_warnings
-DROP TABLE IF EXISTS t1;
---enable_query_log
-
-
-# Start by creating a logfile group
-##################################
-
-CREATE LOGFILE GROUP lg1
-ADD UNDOFILE 'undofile.dat'
-INITIAL_SIZE 16M
-UNDO_BUFFER_SIZE = 1M
-ENGINE=NDB;
-
-ALTER LOGFILE GROUP lg1
-ADD UNDOFILE 'undofile02.dat'
-INITIAL_SIZE = 4M
-ENGINE=NDB;
-
-###################################################
-# Create a tablespace connected to the logfile group
-###################################################
-
-CREATE TABLESPACE ts1
-ADD DATAFILE 'datafile.dat'
-USE LOGFILE GROUP lg1
-INITIAL_SIZE 12M
-ENGINE NDB;
-
-ALTER TABLESPACE ts1
-ADD DATAFILE 'datafile02.dat'
-INITIAL_SIZE = 4M
-ENGINE=NDB;
-
-#################################################################
-
---echo --- Start test 2 partition RANGE testing --
---echo --- Do setup --
-
-
-#################################################
-# Requirment: Create table that is partitioned #
-# by range on year i.e. year(t) and replicate #
-# basice operations such at insert, update #
-# delete between 2 different storage engines #
-# Alter table and ensure table is handled #
-# Correctly on the slave #
-#################################################
-
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
- bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
- f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
- y YEAR, t DATE)
- TABLESPACE ts1 STORAGE DISK
- ENGINE=NDB
- PARTITION BY RANGE (YEAR(t))
- (PARTITION p0 VALUES LESS THAN (1901),
- PARTITION p1 VALUES LESS THAN (1946),
- PARTITION p2 VALUES LESS THAN (1966),
- PARTITION p3 VALUES LESS THAN (1986),
- PARTITION p4 VALUES LESS THAN (2005),
- PARTITION p5 VALUES LESS THAN MAXVALUE);
-
---echo --- Show table on master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Show table on slave --
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- Check that simple Alter statements are replicated correctly ---
-
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
-
---echo --- Show the new improved table on the master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Make sure that our tables on slave are still same engine ---
---echo --- and that the alter statements replicated correctly ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
---enable_query_log
-
---source include/rpl_multi_engine3.inc
-
---echo --- End test 2 partition RANGE testing ---
---echo --- Do Cleanup ---
-
-DROP TABLE IF EXISTS t1;
-
-########################################################
-
---echo --- Start test 3 partition LIST testing ---
---echo --- Do setup ---
-#################################################
-
-
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
- bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
- f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
- y YEAR, t DATE)
- TABLESPACE ts1 STORAGE DISK
- ENGINE=NDB
- PARTITION BY LIST(id)
- (PARTITION p0 VALUES IN (2, 4),
- PARTITION p1 VALUES IN (42, 142));
-
---echo --- Test 3 Alter to add partition ---
-
-ALTER TABLE t1 ADD PARTITION (PARTITION p2 VALUES IN (412));
-
---echo --- Show table on master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Show table on slave ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- Check that simple Alter statements are replicated correctly ---
-
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
-
---echo --- Show the new improved table on the master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Make sure that our tables on slave are still same engine ---
---echo --- and that the alter statements replicated correctly ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- End test 3 partition LIST testing ---
---echo --- Do Cleanup --
-
-DROP TABLE IF EXISTS t1;
-
-########################################################
-
---echo --- Start test 4 partition HASH testing ---
---echo --- Do setup ---
-#################################################
-
-
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
- bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
- f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
- y YEAR, t DATE)
- TABLESPACE ts1 STORAGE DISK
- ENGINE=NDB
- PARTITION BY HASH( YEAR(t) )
- PARTITIONS 4;
-
---echo --- show that tables have been created correctly ---
-
-SHOW CREATE TABLE t1;
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- Check that simple Alter statements are replicated correctly ---
-
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
-
---echo --- Show the new improved table on the master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Make sure that our tables on slave are still same engine ---
---echo --- and that the alter statements replicated correctly ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- End test 4 partition HASH testing ---
---echo --- Do Cleanup --
-
-DROP TABLE IF EXISTS t1;
-
-########################################################
-
---echo --- Start test 5 partition by key testing ---
---echo --- Create Table Section ---
-
-#################################################
-
-CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(63),
- bc CHAR(63), d DECIMAL(10,4) DEFAULT 0,
- f FLOAT DEFAULT 0, total BIGINT UNSIGNED,
- y YEAR, t DATE,PRIMARY KEY(id))
- TABLESPACE ts1 STORAGE DISK
- ENGINE=NDB
- PARTITION BY KEY()
- PARTITIONS 4;
-
---echo --- Show that tables on master are ndbcluster tables ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Show that tables on slave ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
-# Okay lets see how it holds up to table changes
---echo --- Check that simple Alter statements are replicated correctly ---
-
-ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total);
-
---echo --- Show the new improved table on the master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Make sure that our tables on slave are still right type ---
---echo --- and that the alter statements replicated correctly ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- Check that simple Alter statements are replicated correctly ---
-
-ALTER TABLE t1 MODIFY vc VARCHAR(255);
-
---echo --- Show the new improved table on the master ---
-
-SHOW CREATE TABLE t1;
-
---echo --- Make sure that our tables on slave are still same engine ---
---echo --- and that the alter statements replicated correctly ---
-
-sync_slave_with_master;
-SHOW CREATE TABLE t1;
-
---echo --- Perform basic operation on master ---
---echo --- and ensure replicated correctly ---
-
---source include/rpl_multi_engine3.inc
-
---echo --- End test 5 key partition testing ---
---echo --- Do Cleanup ---
-
-DROP TABLE IF EXISTS t1;
-alter tablespace ts1
-drop datafile 'datafile.dat'
-engine=ndb;
-alter tablespace ts1
-drop datafile 'datafile02.dat'
-engine=ndb;
-DROP TABLESPACE ts1 ENGINE=NDB;
-DROP LOGFILE GROUP lg1 ENGINE=NDB;
---sync_slave_with_master
-
-# End of 5.1 test case
diff --git a/mysql-test/t/rpl_ndb_innodb2ndb-master.opt b/mysql-test/t/rpl_ndb_innodb2ndb-master.opt
index 248f9e60566..627becdbfb5 100644
--- a/mysql-test/t/rpl_ndb_innodb2ndb-master.opt
+++ b/mysql-test/t/rpl_ndb_innodb2ndb-master.opt
@@ -1 +1 @@
---innodb --binlog-format=row
+--innodb
diff --git a/mysql-test/t/rpl_ndb_innodb2ndb-slave.opt b/mysql-test/t/rpl_ndb_innodb2ndb-slave.opt
index d6f11dcd7bc..7f9eb96dff1 100644
--- a/mysql-test/t/rpl_ndb_innodb2ndb-slave.opt
+++ b/mysql-test/t/rpl_ndb_innodb2ndb-slave.opt
@@ -1 +1 @@
---binlog-format=row --default-storage-engine=ndbcluster
+--default-storage-engine=ndbcluster
diff --git a/mysql-test/t/rpl_ndb_myisam2ndb-slave.opt b/mysql-test/t/rpl_ndb_myisam2ndb-slave.opt
index b7990823676..701dddb075b 100644
--- a/mysql-test/t/rpl_ndb_myisam2ndb-slave.opt
+++ b/mysql-test/t/rpl_ndb_myisam2ndb-slave.opt
@@ -1 +1 @@
---default-storage-engine=ndbcluster --binlog-format=row
+--default-storage-engine=ndbcluster
diff --git a/mysql-test/t/rpl_stm_until.test b/mysql-test/t/rpl_stm_until.test
index 1bd87db88cb..9a4e4471fe1 100644
--- a/mysql-test/t/rpl_stm_until.test
+++ b/mysql-test/t/rpl_stm_until.test
@@ -32,7 +32,7 @@ wait_for_slave_to_stop;
select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 9 # 11 # 23 # 33 #
-show slave status;
+--query_vertical SHOW SLAVE STATUS
# this should fail right after start
start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291;
@@ -42,7 +42,7 @@ sleep 2;
wait_for_slave_to_stop;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 9 # 11 # 23 # 33 #
-show slave status;
+--query_vertical SHOW SLAVE STATUS
# try replicate all up to and not including the second insert to t2;
start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
@@ -51,7 +51,7 @@ wait_for_slave_to_stop;
select * from t2;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 9 # 11 # 23 # 33 #
-show slave status;
+--query_vertical SHOW SLAVE STATUS
# clean up
start slave;
@@ -68,7 +68,7 @@ wait_for_slave_to_stop;
# here the sql slave thread should be stopped
--replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004
--replace_column 1 # 9 # 23 # 33 #
-show slave status;
+--query_vertical SHOW SLAVE STATUS
#testing various error conditions
--error 1277
diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test
index 93e22e74597..0d91a9f8e91 100644
--- a/mysql-test/t/rpl_temporary.test
+++ b/mysql-test/t/rpl_temporary.test
@@ -165,24 +165,19 @@ drop table t5;
# value was set up at the moment of temp table creation
#
connection con1;
-set @session.pseudo_thread_id=100;
+set @@session.pseudo_thread_id=100;
create temporary table t101 (id int);
create temporary table t102 (id int);
-set @session.pseudo_thread_id=200;
+set @@session.pseudo_thread_id=200;
create temporary table t201 (id int);
-create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
-
-#
-# Don't kill our own connection to the server as
-# the result code differs depending on platform.
-#
-# Select the id to kill into a variable of mysqltest
-let $con1_id= `select connection_id()`;
-# Switch connection to avoid killing our own connection
-connection master;
---disable_query_log
-eval kill $con1_id;
---enable_query_log
+#create temporary table `t``201` (id int);
+# emulate internal temp table not to come to binlog
+create temporary table `#sql_not_user_table202` (id int);
+set @@session.pseudo_thread_id=300;
+create temporary table t301 (id int);
+create temporary table t302 (id int);
+create temporary table `#sql_not_user_table303` (id int);
+disconnect con1;
#now do something to show that slave is ok after DROP temp tables
connection master;
@@ -195,4 +190,17 @@ select * from t1 /* must be 1 */;
connection master;
drop table t1;
-# End of 5.1 tests
+
+#
+#14157: utf8 encoding in binlog without set character_set_client
+#
+--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=latin1 test -e 'create table t1 (a int); set names latin1; create temporary table `äöüÄÖÜ` (a int); insert into `äöüÄÖÜ` values (1); insert into t1 select * from `äöüÄÖÜ`'
+
+sync_slave_with_master;
+#connection slave;
+select * from t1;
+
+connection master;
+drop table t1;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 4b6ae921b9b..8cd15463c62 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -1296,9 +1296,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle';
# The next should give an error
#
--- error 1072
+-- error 1176
explain select fld3 from t2 ignore index (fld3,not_used);
--- error 1072
+-- error 1176
explain select fld3 from t2 use index (not_used);
#
@@ -2264,6 +2264,21 @@ insert into t2 values(1,1);
select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2));
drop table t1,t2;
+#
+# Bug #17873: confusing error message when IGNORE INDEX refers a column name
+#
+
+CREATE TABLE t1 (a int, INDEX idx(a));
+INSERT INTO t1 VALUES (2), (3), (1);
+
+EXPLAIN SELECT * FROM t1 IGNORE INDEX (idx);
+--error 1176
+EXPLAIN SELECT * FROM t1 IGNORE INDEX (a);
+--error 1176
+EXPLAIN SELECT * FROM t1 FORCE INDEX (a);
+
+DROP TABLE t1;
+
# End of 4.1 tests
#
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 0f71860ab9d..885d76ff3f9 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -5833,6 +5833,52 @@ DROP PROCEDURE bug18589_p2|
#
+# BUG#18037: Server crash when returning system variable in stored procedures
+# BUG#19633: Stack corruption in fix_fields()/THD::rollback_item_tree_changes()
+#
+
+# Prepare.
+
+--disable_warnings
+DROP FUNCTION IF EXISTS bug18037_f1|
+DROP PROCEDURE IF EXISTS bug18037_p1|
+DROP PROCEDURE IF EXISTS bug18037_p2|
+--enable_warnings
+
+# Test case.
+
+CREATE FUNCTION bug18037_f1() RETURNS INT
+BEGIN
+ RETURN @@server_id;
+END|
+
+CREATE PROCEDURE bug18037_p1()
+BEGIN
+ DECLARE v INT DEFAULT @@server_id;
+END|
+
+CREATE PROCEDURE bug18037_p2()
+BEGIN
+ CASE @@server_id
+ WHEN -1 THEN
+ SELECT 0;
+ ELSE
+ SELECT 1;
+ END CASE;
+END|
+
+SELECT bug18037_f1()|
+CALL bug18037_p1()|
+CALL bug18037_p2()|
+
+# Cleanup.
+
+DROP FUNCTION bug18037_f1|
+DROP PROCEDURE bug18037_p1|
+DROP PROCEDURE bug18037_p2|
+
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
index 54260b09331..212150e057c 100644
--- a/mysql-test/t/strict.test
+++ b/mysql-test/t/strict.test
@@ -1145,3 +1145,13 @@ create table t1(a bit(2));
insert into t1 values(b'101');
select * from t1;
drop table t1;
+
+#
+# Bug#17626 CREATE TABLE ... SELECT failure with TRADITIONAL SQL mode
+#
+set sql_mode='traditional';
+create table t1 (date date not null);
+create table t2 select date from t1;
+show create table t2;
+drop table t2,t1;
+set @@sql_mode= @org_mode;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 9f4d89a7e50..8916a5cec6d 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -2100,3 +2100,34 @@ CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1);
SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1);
DROP TABLE t1;
+
+#
+# Bug#19077: A nested materialized derived table is used before being populated.
+#
+create table t1 (i int, j bigint);
+insert into t1 values (1, 2), (2, 2), (3, 2);
+select * from (select min(i) from t1 where j=(select * from (select min(j) from t1) t2)) t3;
+drop table t1;
+
+#
+# Bug#19700: subselect returning BIGINT always returned it as SIGNED
+#
+CREATE TABLE t1 (i BIGINT UNSIGNED);
+INSERT INTO t1 VALUES (10000000000000000000); -- > MAX SIGNED BIGINT 9323372036854775807
+INSERT INTO t1 VALUES (1);
+
+CREATE TABLE t2 (i BIGINT UNSIGNED);
+INSERT INTO t2 VALUES (10000000000000000000); -- same as first table
+INSERT INTO t2 VALUES (1);
+
+/* simple test */
+SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i;
+
+/* subquery test */
+SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2);
+
+/* subquery test with cast*/
+SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED);
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 1b0f7896811..7aa79f0eb40 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -540,7 +540,42 @@ select @@version, @@version_comment, @@version_compile_machine,
@@version_compile_os;
#
-# Bug #19263: variables.test doesn't clean up after itself (II/II -- restore)
+# Bug #1039: make tmpdir and datadir available as @@variables (also included
+# basedir)
+#
+# Don't actually output, since it depends on the system
+--replace_column 1 # 2 # 3 #
+select @@basedir, @@datadir, @@tmpdir;
+--replace_column 2 #
+show variables like 'basedir';
+--replace_column 2 #
+show variables like 'datadir';
+--replace_column 2 #
+show variables like 'tmpdir';
+
+#
+# Bug #19606: make ssl settings available via SHOW VARIABLES and @@variables
+#
+# Don't actually output, since it depends on the system
+--replace_column 1 # 2 # 3 # 4 # 5 #
+select @@ssl_ca, @@ssl_capath, @@ssl_cert, @@ssl_cipher, @@ssl_key;
+--replace_column 2 #
+show variables like 'ssl%';
+
+#
+# Bug #19616: make log_queries_not_using_indexes available in SHOW VARIABLES
+# and as @@log_queries_not_using_indexes
+#
+select @@log_queries_not_using_indexes;
+show variables like 'log_queries_not_using_indexes';
+
+--echo End of 5.0 tests
+
+# This is at the very after the versioned tests, since it involves doing
+# cleanup
+#
+# Bug #19263: variables.test doesn't clean up after itself (II/II --
+# restore)
#
set global binlog_cache_size =@my_binlog_cache_size;
set global connect_timeout =@my_connect_timeout;
@@ -569,5 +604,3 @@ set global server_id =@my_server_id;
set global slow_launch_time =@my_slow_launch_time;
set global storage_engine =@my_storage_engine;
set global thread_cache_size =@my_thread_cache_size;
-
---echo End of 5.0 tests
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 783d1182c64..0db97f6d4af 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -516,7 +516,7 @@ drop table t1;
#
create table t1 (a int, b int);
create view v1 as select a, sum(b) from t1 group by a;
--- error 1072
+-- error 1176
select b from v1 use index (some_index) where b=1;
drop view v1;
drop table t1;
@@ -2533,3 +2533,71 @@ SELECT * FROM v1;
DROP VIEW v1;
DROP TABLE t1;
+
+#
+# Bug#19077: A nested materialized view is used before being populated.
+#
+CREATE TABLE t1 (i INT, j BIGINT);
+INSERT INTO t1 VALUES (1, 2), (2, 2), (3, 2);
+CREATE VIEW v1 AS SELECT MIN(j) AS j FROM t1;
+CREATE VIEW v2 AS SELECT MIN(i) FROM t1 WHERE j = ( SELECT * FROM v1 );
+SELECT * FROM v2;
+DROP VIEW v2, v1;
+DROP TABLE t1;
+
+#
+# Bug #19573: VIEW with HAVING that refers an alias name
+#
+
+CREATE TABLE t1(
+ fName varchar(25) NOT NULL,
+ lName varchar(25) NOT NULL,
+ DOB date NOT NULL,
+ uID int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY);
+
+INSERT INTO t1(fName, lName, DOB) VALUES
+ ('Hank', 'Hill', '1964-09-29'),
+ ('Tom', 'Adams', '1908-02-14'),
+ ('Homer', 'Simpson', '1968-03-05');
+
+CREATE VIEW v1 AS
+ SELECT (year(now())-year(DOB)) AS Age
+ FROM t1 HAVING Age < 75;
+SHOW CREATE VIEW v1;
+
+SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75;
+SELECT * FROM v1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# Bug #19089: wrong inherited dafault values in temp table views
+#
+
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx');
+INSERT INTO t1(id) VALUES (1), (2), (3), (4);
+INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy');
+SELECT * FROM t1;
+
+CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a;
+SELECT * FROM v1;
+
+CREATE TABLE t2 SELECT * FROM v1;
+INSERT INTO t2(m) VALUES (0);
+SELECT * FROM t2;
+
+DROP VIEW v1;
+DROP TABLE t1,t2;
+
+CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b');
+INSERT INTO t1(id) VALUES (1), (2), (3);
+INSERT INTO t1 VALUES (4,'a');
+SELECT * FROM t1;
+
+CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e;
+CREATE TABLE t2 SELECT * FROM v1;
+SELECT * FROM t2;
+
+DROP VIEW v1;
+DROP TABLE IF EXISTS t1,t2;
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index 8deff474587..aa420689149 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -3,7 +3,7 @@
--disable_warnings
drop database if exists mysqltest;
-drop view if exists v1;
+drop view if exists v1,v2,v3;
--enable_warnings
@@ -718,3 +718,98 @@ show create view v1;
show create view v2;
drop view v1;
drop view v2;
+
+#
+# Bug#18681: View privileges are broken
+#
+CREATE DATABASE mysqltest1;
+CREATE USER readonly@localhost;
+CREATE TABLE mysqltest1.t1 (x INT);
+INSERT INTO mysqltest1.t1 VALUES (1), (2);
+CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1;
+CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1;
+GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly;
+GRANT SELECT ON mysqltest1.v_ts TO readonly;
+GRANT INSERT ON mysqltest1.v_ti TO readonly;
+GRANT UPDATE ON mysqltest1.v_tu TO readonly;
+GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly;
+GRANT DELETE ON mysqltest1.v_td TO readonly;
+GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly;
+
+CONNECT (n1,localhost,readonly,,);
+CONNECTION n1;
+
+--error 1356
+SELECT * FROM mysqltest1.v_t1;
+--error 1356
+INSERT INTO mysqltest1.v_t1 VALUES(4);
+--error 1356
+DELETE FROM mysqltest1.v_t1 WHERE x = 1;
+--error 1356
+UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2;
+--error 1356
+UPDATE mysqltest1.v_t1 SET x = 3;
+--error 1356
+DELETE FROM mysqltest1.v_t1;
+--error 1356
+SELECT 1 FROM mysqltest1.v_t1;
+--error 1142
+SELECT * FROM mysqltest1.t1;
+
+SELECT * FROM mysqltest1.v_ts;
+--error 1142
+SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x;
+--error 1142
+SELECT * FROM mysqltest1.v_ti;
+
+--error 1142
+INSERT INTO mysqltest1.v_ts VALUES (100);
+INSERT INTO mysqltest1.v_ti VALUES (100);
+
+--error 1142
+UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100;
+--error 1142
+UPDATE mysqltest1.v_ts SET x= 200;
+UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100;
+UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100;
+UPDATE mysqltest1.v_tu SET x= 200;
+
+--error 1142
+DELETE FROM mysqltest1.v_ts WHERE x= 200;
+--error 1142
+DELETE FROM mysqltest1.v_ts;
+--error 1143
+DELETE FROM mysqltest1.v_td WHERE x= 200;
+DELETE FROM mysqltest1.v_tds WHERE x= 200;
+DELETE FROM mysqltest1.v_td;
+
+CONNECTION default;
+DROP VIEW mysqltest1.v_tds;
+DROP VIEW mysqltest1.v_td;
+DROP VIEW mysqltest1.v_tus;
+DROP VIEW mysqltest1.v_tu;
+DROP VIEW mysqltest1.v_ti;
+DROP VIEW mysqltest1.v_ts;
+DROP VIEW mysqltest1.v_t1;
+DROP TABLE mysqltest1.t1;
+DROP USER readonly@localhost;
+DROP DATABASE mysqltest1;
+
+#
+# BUG#14875: Bad view DEFINER makes SHOW CREATE VIEW fail
+#
+CREATE TABLE t1 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (1), (2), (3);
+CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1;
+--warning 1448
+SHOW CREATE VIEW v;
+--error 1449
+SELECT * FROM v;
+DROP VIEW v;
+DROP TABLE t1;
+USE test;
diff --git a/mysql-test/t/wait_timeout.test b/mysql-test/t/wait_timeout.test
index 1fef3deea3c..9310c3502b9 100644
--- a/mysql-test/t/wait_timeout.test
+++ b/mysql-test/t/wait_timeout.test
@@ -4,10 +4,41 @@
#
# Bug #8731: wait_timeout does not work on Mac OS X
#
+
+
+# Connect with another connection and reset counters
+--disable_query_log
+connect (wait_con,localhost,root,,test,,);
+flush status; # Reset counters
+connection wait_con;
+let $retries=300;
+let $aborted_clients = `SHOW STATUS LIKE 'aborted_clients'`;
+set @aborted_clients= 0;
+--enable_query_log
+
+# Disable reconnect and do the query
+connection default;
--disable_reconnect
select 1;
-# wait_timeout is 1, so we should get disconnected now
---sleep 2
+
+# Switch to wait_con and wait until server has aborted the connection
+--disable_query_log
+connection wait_con;
+while (!`select @aborted_clients`)
+{
+ sleep 0.1;
+ let $aborted_clients = `SHOW STATUS LIKE 'aborted_clients'`;
+ eval set @aborted_clients= SUBSTRING('$aborted_clients', 16)+0;
+
+ dec $retries;
+ if (!$retries)
+ {
+ Failed to detect that client has been aborted;
+ }
+}
+--enable_query_log
+
+connection default;
# When the connection is closed in this way, the error code should
# be consistent see bug#2845 for an explanation
--error 2006
@@ -15,12 +46,41 @@ select 2;
--enable_reconnect
select 3;
+#
# Do the same test as above on a TCP connection
+# (which we get by specifying a ip adress)
+
+# Connect with another connection and reset counters
+--disable_query_log
+connection wait_con;
+flush status; # Reset counters
+let $retries=300;
+let $aborted_clients = `SHOW STATUS LIKE 'aborted_clients'`;
+set @aborted_clients= 0;
+--enable_query_log
+
connect (con1,127.0.0.1,root,,test,$MASTER_MYPORT,);
--disable_reconnect
select 1;
-# wait_timeout is 1, so we should get disconnected now
---sleep 2
+
+# Switch to wait_con and wait until server has aborted the connection
+--disable_query_log
+connection wait_con;
+while (!`select @aborted_clients`)
+{
+ sleep 0.1;
+ let $aborted_clients = `SHOW STATUS LIKE 'aborted_clients'`;
+ eval set @aborted_clients= SUBSTRING('$aborted_clients', 16)+0;
+
+ dec $retries;
+ if (!$retries)
+ {
+ Failed to detect that client has been aborted;
+ }
+}
+--enable_query_log
+
+connection con1;
# When the connection is closed in this way, the error code should
# be consistent see bug#2845 for an explanation
--error 2006
diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp
index b0ba3b03652..9061a71364d 100644
--- a/mysql-test/valgrind.supp
+++ b/mysql-test/valgrind.supp
@@ -112,6 +112,26 @@
}
{
+ pthread strstr uninit
+ Memcheck:Cond
+ fun:strstr
+ obj:/lib/tls/libpthread.so.*
+ obj:/lib/tls/libpthread.so.*
+ fun:call_init
+ fun:_dl_init
+ obj:/lib/ld-*.so
+}
+
+{
+ strlen/_dl_init_paths/dl_main/_dl_sysdep_start(Cond)
+ Memcheck:Cond
+ fun:strlen
+ fun:_dl_init_paths
+ fun:dl_main
+ fun:_dl_sysdep_start
+}
+
+{
pthread errno
Memcheck:Leak
fun:calloc
@@ -220,6 +240,7 @@
fun:kill_server_thread
}
+
# Red Hat AS 4 32 bit
{
dl_relocate_object
@@ -385,3 +406,30 @@
futex(utime)
fun:__lll_mutex_unlock_wake
}
+
+#
+# Warning when printing stack trace (to suppress some not needed warnings)
+#
+
+{
+ vprintf on stacktrace
+ Memcheck:Cond
+ fun:vfprintf
+ fun:uffered_vfprintf
+ fun:vfprintf
+ fun:fprintf
+ fun:print_stacktrace
+}
+
+#
+# Safe warnings, that may happen because of thread scheduling
+#
+
+{
+ dbug initialization
+ Memcheck:Leak
+ fun:malloc
+ fun:DbugMalloc
+ fun:ListAdd
+ fun:_db_set_
+}
diff --git a/mysql-test/valgrind.supp.orig b/mysql-test/valgrind.supp.orig
new file mode 100644
index 00000000000..1a08abcf953
--- /dev/null
+++ b/mysql-test/valgrind.supp.orig
@@ -0,0 +1,189 @@
+#
+# Suppress some common (not fatal) errors in system libraries found by valgrind
+#
+
+#
+# Pthread doesn't free all thread specific memory before program exists
+#
+{
+ pthread allocate_tls memory loss
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:allocate_stack
+ fun:pthread_create@@GLIBC_2.1
+}
+
+{
+ pthread allocate_dtv memory loss
+ Memcheck:Leak
+ fun:calloc
+ fun:allocate_dtv
+ fun:_dl_allocate_tls_storage
+ fun:__GI__dl_allocate_tls
+ fun:pthread_create
+}
+
+{
+ pthread allocate_dtv memory loss second
+ Memcheck:Leak
+ fun:calloc
+ fun:allocate_dtv
+ fun:_dl_allocate_tls
+ fun:pthread_create*
+}
+
+{
+ pthread allocate_dtv memory loss second
+ Memcheck:Leak
+ fun:calloc
+ fun:allocate_dtv
+ fun:_dl_allocate_tls
+ fun:pthread_create*
+}
+
+{
+ pthread memalign memory loss
+ Memcheck:Leak
+ fun:memalign
+ fun:_dl_allocate_tls_storage
+ fun:__GI__dl_allocate_tls
+ fun:pthread_create
+}
+
+{
+ pthread pthread_key_create
+ Memcheck:Leak
+ fun:malloc
+ fun:*
+ fun:*
+ fun:pthread_key_create
+ fun:my_thread_global_init
+}
+
+{
+ pthread strstr uninit
+ Memcheck:Cond
+ fun:strstr
+ obj:/lib/tls/libpthread.so.*
+ obj:/lib/tls/libpthread.so.*
+ fun:call_init
+ fun:_dl_init
+ obj:/lib/ld-*.so
+}
+
+{
+ pthread strstr uninit
+ Memcheck:Cond
+ fun:strstr
+ obj:/lib/tls/libpthread.so.*
+ obj:/lib/tls/libpthread.so.*
+ fun:call_init
+ fun:_dl_init
+ obj:/lib/ld-*.so
+}
+
+{
+ pthread errno
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlsym
+ fun:__errno_location
+}
+
+
+#
+# Warnings in libz becasue it works with aligned memory(?)
+#
+
+{
+ libz tr_flush_block
+ Memcheck:Cond
+ fun:_tr_flush_block
+ fun:deflate_slow
+ fun:deflate
+ fun:do_flush
+ fun:gzclose
+}
+
+{
+ libz tr_flush_block2
+ Memcheck:Cond
+ fun:_tr_flush_block
+ fun:deflate_slow
+ fun:deflate
+ fun:compress2
+}
+
+{
+ libz longest_match
+ Memcheck:Cond
+ fun:longest_match
+ fun:deflate_slow
+ fun:deflate
+ fun:do_flush
+}
+
+{
+ libz longest_match2
+ Memcheck:Cond
+ fun:longest_match
+ fun:deflate_slow
+ fun:deflate
+ fun:compress2
+}
+
+{
+ libz deflate
+ Memcheck:Cond
+ obj:*/libz.so.*
+ obj:*/libz.so.*
+ fun:deflate
+ fun:compress2
+}
+
+{
+ libz deflate2
+ Memcheck:Cond
+ obj:*/libz.so.*
+ obj:*/libz.so.*
+ fun:deflate
+ obj:*/libz.so.*
+ fun:gzflush
+}
+
+{
+ libz deflate3
+ Memcheck:Cond
+ obj:*/libz.so.*
+ obj:*/libz.so.*
+ fun:deflate
+ fun:do_flush
+}
+
+#
+# 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
+}
+
+#
+# Warning when printing stack trace (to suppress some not needed warnings)
+#
+
+{
+ vprintf on stacktrace
+ Memcheck:Cond
+ fun:vfprintf
+ fun:uffered_vfprintf
+ fun:vfprintf
+ fun:fprintf
+ fun:print_stacktrace
+}
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 1241e8cdded..2838427e9e0 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -20,8 +20,7 @@ MYSQLBASEdir= $(prefix)
INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
-LDADD = libmysys.a ../dbug/libdbug.a \
- ../strings/libmystrings.a
+LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a
noinst_HEADERS = mysys_priv.h my_static.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 \
@@ -32,7 +31,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.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_vle.c my_atomic.c \
my_fopen.c my_fstream.c my_getsystime.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 \
@@ -40,7 +39,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_pack.c mf_unixpath.c mf_strip.c \
mf_wcomp.c mf_wfile.c my_gethwaddr.c \
mf_qsort.c mf_qsort2.c mf_sort.c \
- ptr_cmp.c mf_radix.c queues.c \
+ ptr_cmp.c mf_radix.c queues.c my_getncpus.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 \
@@ -64,7 +63,6 @@ libmysys_a_LIBADD = @THREAD_LOBJECTS@
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
# charset2html_DEPENDENCIES= $(LIBRARIES)
-EXTRA_PROGRAMS =
DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
diff --git a/mysys/base64.c b/mysys/base64.c
index 60218993c42..610797dd2ce 100644
--- a/mysys/base64.c
+++ b/mysys/base64.c
@@ -14,9 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <base64.h>
+#include <my_global.h>
#include <m_string.h> /* strchr() */
#include <m_ctype.h> /* my_isspace() */
+#include <base64.h>
#ifndef MAIN
diff --git a/mysys/default.c b/mysys/default.c
index 580bcc19eca..863ebc37dbc 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -244,7 +244,8 @@ err:
handle_option_ctx structure.
group_name The name of the group the option belongs to.
option The very option to be processed. It is already
- prepared to be used in argv (has -- prefix)
+ prepared to be used in argv (has -- prefix). If it
+ is NULL, we are handling a new group (section).
DESCRIPTION
This handler checks whether a group is one of the listed and adds an option
@@ -263,6 +264,9 @@ static int handle_default_option(void *in_ctx, const char *group_name,
char *tmp;
struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
+ if (!option)
+ return 0;
+
if (find_type((char *)group_name, ctx->group, 3))
{
if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1)))
@@ -719,6 +723,10 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
end[0]=0;
strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096));
+
+ /* signal that a new group is found */
+ opt_handler(handler_ctx, curr_gr, NULL);
+
continue;
}
if (!found_group)
@@ -755,7 +763,9 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
value_end=value;
/* remove quotes around argument */
- if ((*value == '\"' || *value == '\'') && *value == value_end[-1])
+ if ((*value == '\"' || *value == '\'') && /* First char is quote */
+ (value + 1 < value_end ) && /* String is longer than 1 */
+ *value == value_end[-1] ) /* First char is equal to last char */
{
value++;
value_end--;
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index 0f58b8a930c..8dbcac699ea 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -40,11 +40,13 @@ static char *add_option(char *dst, const char *option_value,
SYNOPSYS
modify_defaults_file()
file_location The location of configuration file to edit
- option option to look for
- option value The value of the option we would like to set
- section_name the name of the section
- remove_option This is true if we want to remove the option.
- False otherwise.
+ option The name of the option to look for (can be NULL)
+ option value The value of the option we would like to set (can be NULL)
+ section_name The name of the section (must be NOT NULL)
+ remove_option This defines what we want to remove:
+ - MY_REMOVE_NONE -- nothing to remove;
+ - MY_REMOVE_OPTION -- remove the specified option;
+ - MY_REMOVE_SECTION -- remove the specified section;
IMPLEMENTATION
We open the option file first, then read the file line-by-line,
looking for the section we need. At the same time we put these lines
@@ -67,7 +69,9 @@ int modify_defaults_file(const char *file_location, const char *option,
FILE *cnf_file;
MY_STAT file_stat;
char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
- uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size;
+ uint opt_len= 0;
+ uint optval_len= 0;
+ uint sect_len, nr_newlines= 0, buffer_size;
my_bool in_section= FALSE, opt_applied= 0;
uint reserve_extended;
uint new_opt_len;
@@ -81,8 +85,11 @@ int modify_defaults_file(const char *file_location, const char *option,
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
goto malloc_err;
- opt_len= (uint) strlen(option);
- optval_len= (uint) strlen(option_value);
+ if (option && option_value)
+ {
+ opt_len= (uint) strlen(option);
+ optval_len= (uint) strlen(option_value);
+ }
new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
@@ -119,8 +126,8 @@ int modify_defaults_file(const char *file_location, const char *option,
continue;
}
- /* correct the option */
- if (in_section && !strncmp(src_ptr, option, opt_len) &&
+ /* correct the option (if requested) */
+ if (option && in_section && !strncmp(src_ptr, option, opt_len) &&
(*(src_ptr + opt_len) == '=' ||
my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
*(src_ptr + opt_len) == '\0'))
@@ -143,7 +150,12 @@ int modify_defaults_file(const char *file_location, const char *option,
}
else
{
- /* If going to new group and we have option to apply, do it now */
+ /*
+ If we are going to the new group and have an option to apply, do
+ it now. If we are removing a single option or the whole section
+ this will only trigger opt_applied flag.
+ */
+
if (in_section && !opt_applied && *src_ptr == '[')
{
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
@@ -153,7 +165,10 @@ int modify_defaults_file(const char *file_location, const char *option,
for (; nr_newlines; nr_newlines--)
dst_ptr= strmov(dst_ptr, NEWLINE);
- dst_ptr= strmov(dst_ptr, linebuff);
+
+ /* Skip the section if MY_REMOVE_SECTION was given */
+ if (!in_section || remove_option != MY_REMOVE_SECTION)
+ dst_ptr= strmov(dst_ptr, linebuff);
}
/* Look for a section */
if (*src_ptr == '[')
@@ -167,18 +182,31 @@ int modify_defaults_file(const char *file_location, const char *option,
{}
if (*src_ptr != ']')
+ {
+ in_section= FALSE;
continue; /* Missing closing parenthesis. Assume this was no group */
+ }
+
+ if (remove_option == MY_REMOVE_SECTION)
+ dst_ptr= dst_ptr - strlen(linebuff);
+
in_section= TRUE;
}
else
in_section= FALSE; /* mark that this section is of no interest to us */
}
}
- /* File ended. */
- if (!opt_applied && !remove_option && in_section)
+
+ /*
+ File ended. Apply an option or set opt_applied flag (in case of
+ MY_REMOVE_SECTION) so that the changes are saved. Do not do anything
+ if we are removing non-existent option.
+ */
+
+ if (!opt_applied && in_section && (remove_option != MY_REMOVE_OPTION))
{
/* New option still remains to apply at the end */
- if (*(dst_ptr - 1) != '\n')
+ if (!remove_option && *(dst_ptr - 1) != '\n')
dst_ptr= strmov(dst_ptr, NEWLINE);
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
opt_applied= 1;
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 1dab9a47ed8..71d73048a7b 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -84,14 +84,6 @@
#define KEYCACHE_DEBUG_LOG "my_key_cache_debug.log"
*/
-#if defined(MSDOS) && !defined(M_IC80386)
-/* we nead much memory */
-#undef my_malloc_lock
-#undef my_free_lock
-#define my_malloc_lock(A,B) halloc((long) (A/IO_SIZE),IO_SIZE)
-#define my_free_lock(A,B) hfree(A)
-#endif /* defined(MSDOS) && !defined(M_IC80386) */
-
#define STRUCT_PTR(TYPE, MEMBER, a) \
(TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
diff --git a/mysys/mf_path.c b/mysys/mf_path.c
index cdaee74dd2c..571c4aa9fba 100644
--- a/mysys/mf_path.c
+++ b/mysys/mf_path.c
@@ -73,7 +73,7 @@ my_string my_path(my_string to, const char *progname,
/* test if file without filename is found in path */
/* Returns to if found and to has dirpart if found, else NullS */
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#define F_OK 0
#define PATH_SEP ';'
#define PROGRAM_EXTENSION ".exe"
diff --git a/mysys/mf_tempfile.c b/mysys/mf_tempfile.c
index b079b9ec8e3..4f6cbd2f243 100644
--- a/mysys/mf_tempfile.c
+++ b/mysys/mf_tempfile.c
@@ -24,7 +24,7 @@
#endif
#ifdef HAVE_TEMPNAM
-#if !defined(MSDOS) && !defined(__NETWARE__)
+#if !defined(__NETWARE__)
extern char **environ;
#endif
#endif
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 871de8de0b8..9255d716919 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -156,7 +156,7 @@ int check_if_legal_tablename(const char *name)
}
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
+#if defined(__WIN__) || defined(__EMX__)
/*
@@ -199,4 +199,4 @@ int check_if_legal_filename(const char *path)
DBUG_RETURN(0);
}
-#endif /* defined(MSDOS) || defined(__WIN__) || defined(__EMX__) */
+#endif /* defined(__WIN__) || defined(__EMX__) */
diff --git a/mysys/my_atomic.c b/mysys/my_atomic.c
new file mode 100644
index 00000000000..21b80f0f6a1
--- /dev/null
+++ b/mysys/my_atomic.c
@@ -0,0 +1,46 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+#ifndef HAVE_INLINE
+/*
+ the following will cause all inline functions to be instantiated
+*/
+#define HAVE_INLINE
+#define static extern
+#endif
+
+#include <my_atomic.h>
+
+/*
+ checks that the current build of atomic ops
+ can run on this machine
+
+ RETURN
+ ATOMIC_xxx values, see my_atomic.h
+*/
+int my_atomic_initialize()
+{
+ /* currently the only thing worth checking is SMP/UP issue */
+#ifdef MY_ATOMIC_MODE_DUMMY
+ return my_getncpus() == 1 ? MY_ATOMIC_OK : MY_ATOMIC_NOT_1CPU;
+#else
+ return MY_ATOMIC_OK;
+#endif
+}
+
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index 70edb507b5f..92b0cbb1371 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -46,8 +46,8 @@ void create_last_word_mask(MY_BITMAP *map)
unsigned int const used= 1U + ((map->n_bits-1U) & 0x7U);
/*
- * Create a mask with the upper 'unused' bits set and the lower 'used'
- * bits clear. The bits within each byte is stored in big-endian order.
+ Create a mask with the upper 'unused' bits set and the lower 'used'
+ bits clear. The bits within each byte is stored in big-endian order.
*/
unsigned char const mask= (~((1 << used) - 1)) & 255;
@@ -60,13 +60,11 @@ void create_last_word_mask(MY_BITMAP *map)
unsigned char *ptr= (unsigned char*)&map->last_word_mask;
map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
- switch (no_bytes_in_map(map)&3)
- {
+ switch (no_bytes_in_map(map) & 3) {
case 1:
map->last_word_mask= ~0U;
ptr[0]= mask;
return;
-
case 2:
map->last_word_mask= ~0U;
ptr[0]= 0;
@@ -84,6 +82,7 @@ void create_last_word_mask(MY_BITMAP *map)
}
}
+
static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused)))
{
#ifdef THREAD
@@ -101,37 +100,41 @@ static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
}
-my_bool bitmap_init(MY_BITMAP *map, uint32 *buf, uint n_bits,
+my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
my_bool thread_safe)
{
DBUG_ENTER("bitmap_init");
- DBUG_ASSERT(n_bits > 0);
if (!buf)
{
- uint size_in_bytes= ((n_bits+31)/32)*4
+ uint size_in_bytes= bitmap_buffer_size(n_bits);
+ uint extra= 0;
#ifdef THREAD
- +(thread_safe ? sizeof(pthread_mutex_t) : 0)
+ if (thread_safe)
+ {
+ size_in_bytes= ALIGN_SIZE(size_in_bytes);
+ extra= sizeof(pthread_mutex_t);
+ }
+ map->mutex= 0;
#endif
- ;
- if (!(buf= (uint32*) my_malloc(size_in_bytes, MYF(MY_WME))))
+ if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
DBUG_RETURN(1);
- }
#ifdef THREAD
- else
- DBUG_ASSERT(thread_safe == 0);
+ if (thread_safe)
+ {
+ map->mutex= (pthread_mutex_t *) ((char*) buf + size_in_bytes);
+ pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
+ }
#endif
+ }
#ifdef THREAD
- if (thread_safe)
+ else
{
- map->mutex=(pthread_mutex_t *)buf;
- pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
- buf+= sizeof(pthread_mutex_t)/4;
+ DBUG_ASSERT(thread_safe == 0);
}
- else
- map->mutex=0;
#endif
+
map->bitmap= buf;
- map->n_bits=n_bits;
+ map->n_bits= n_bits;
create_last_word_mask(map);
bitmap_clear_all(map);
DBUG_RETURN(0);
@@ -144,15 +147,10 @@ void bitmap_free(MY_BITMAP *map)
if (map->bitmap)
{
#ifdef THREAD
- char *buf= (char *)map->mutex;
- if (buf)
+ if (map->mutex)
pthread_mutex_destroy(map->mutex);
- else
- buf=(char*) map->bitmap;
- my_free(buf, MYF(0));
-#else
- my_free((char*) map->bitmap, MYF(0));
#endif
+ my_free((char*) map->bitmap, MYF(0));
map->bitmap=0;
}
DBUG_VOID_RETURN;
@@ -205,6 +203,40 @@ my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
return res;
}
+/*
+ test if bit already set and clear it if it was set(thread unsafe method)
+
+ SYNOPSIS
+ bitmap_fast_test_and_set()
+ MAP bit map struct
+ BIT bit number
+
+ RETURN
+ 0 bit was not set
+ !=0 bit was set
+*/
+
+my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
+{
+ uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
+ uchar bit= 1 << ((bitmap_bit) & 7);
+ uchar res= (*byte) & bit;
+ *byte&= ~bit;
+ return res;
+}
+
+
+my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
+{
+ my_bool res;
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
+ bitmap_lock(map);
+ res= bitmap_fast_test_and_clear(map, bitmap_bit);
+ bitmap_unlock(map);
+ return res;
+}
+
+
uint bitmap_set_next(MY_BITMAP *map)
{
uint bit_found;
@@ -230,7 +262,6 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
*m++= (1 << prefix_bits)-1;
if ((d= no_bytes_in_map(map)-prefix_bytes))
bzero(m, d);
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits*/
}
@@ -247,7 +278,7 @@ my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
if (*m++ != 0xff)
return 0;
- *map->last_word_ptr^= map->last_word_mask; /*Clear bits*/
+ *map->last_word_ptr&= ~map->last_word_mask; /*Clear bits*/
res= 0;
if (prefix_bits && *m++ != (1 << prefix_bits)-1)
goto ret;
@@ -257,15 +288,15 @@ my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
goto ret;
res= 1;
ret:
- *map->last_word_ptr|= map->last_word_mask; /*Set bits again*/
return res;
}
my_bool bitmap_is_set_all(const MY_BITMAP *map)
{
- uint32 *data_ptr= map->bitmap;
- uint32 *end= map->last_word_ptr;
+ my_bitmap_map *data_ptr= map->bitmap;
+ my_bitmap_map *end= map->last_word_ptr;
+ *map->last_word_ptr |= map->last_word_mask;
for (; data_ptr <= end; data_ptr++)
if (*data_ptr != 0xFFFFFFFF)
return FALSE;
@@ -275,9 +306,9 @@ my_bool bitmap_is_set_all(const MY_BITMAP *map)
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
- uint32 *data_ptr= map->bitmap;
- uint32 *end;
- if (*map->last_word_ptr != map->last_word_mask)
+ my_bitmap_map *data_ptr= map->bitmap;
+ my_bitmap_map *end;
+ if (*map->last_word_ptr & ~map->last_word_mask)
return FALSE;
end= map->last_word_ptr;
for (; data_ptr < end; data_ptr++)
@@ -286,16 +317,18 @@ my_bool bitmap_is_clear_all(const MY_BITMAP *map)
return TRUE;
}
+/* Return TRUE if map1 is a subset of map2 */
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
- uint32 *m1= map1->bitmap, *m2= map2->bitmap, *end;
+ my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
map1->n_bits==map2->n_bits);
end= map1->last_word_ptr;
-
+ *map1->last_word_ptr &= ~map1->last_word_mask;
+ *map2->last_word_ptr &= ~map2->last_word_mask;
while (m1 <= end)
{
if ((*m1++) & ~(*m2++))
@@ -304,16 +337,36 @@ my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
return 1;
}
+/* True if bitmaps has any common bits */
+
+my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
+{
+ my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
+
+ DBUG_ASSERT(map1->bitmap && map2->bitmap &&
+ map1->n_bits==map2->n_bits);
+
+ end= map1->last_word_ptr;
+ *map1->last_word_ptr &= ~map1->last_word_mask;
+ *map2->last_word_ptr &= ~map2->last_word_mask;
+ while (m1 <= end)
+ {
+ if ((*m1++) & (*m2++))
+ return 1;
+ }
+ return 0;
+}
+
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
{
- uint32 *to= map->bitmap, *from= map2->bitmap, *end;
+ my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
DBUG_ASSERT(map->bitmap && map2->bitmap);
end= to+min(len,len2);
- *map2->last_word_ptr^= map2->last_word_mask; /*Clear last bits in map2*/
+ *map2->last_word_ptr&= ~map2->last_word_mask; /*Clear last bits in map2*/
while (to < end)
*to++ &= *from++;
@@ -323,8 +376,6 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
while (to < end)
*to++=0;
}
- *map2->last_word_ptr|= map2->last_word_mask; /*Set last bits in map*/
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits in map2*/
}
@@ -356,13 +407,12 @@ void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
while (to < end)
*to++= use_byte;
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits again*/
}
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
{
- uint32 *to= map->bitmap, *from= map2->bitmap, *end;
+ my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
DBUG_ASSERT(map->bitmap && map2->bitmap &&
map->n_bits==map2->n_bits);
@@ -370,13 +420,12 @@ void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
while (to <= end)
*to++ &= ~(*from++);
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits again*/
}
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
{
- uint32 *to= map->bitmap, *from= map2->bitmap, *end;
+ my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
DBUG_ASSERT(map->bitmap && map2->bitmap &&
map->n_bits==map2->n_bits);
@@ -389,25 +438,23 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
{
- uint32 *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
+ my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT(map->bitmap && map2->bitmap &&
map->n_bits==map2->n_bits);
while (to <= end)
*to++ ^= *from++;
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits again*/
}
void bitmap_invert(MY_BITMAP *map)
{
- uint32 *to= map->bitmap, *end;
+ my_bitmap_map *to= map->bitmap, *end;
DBUG_ASSERT(map->bitmap);
end= map->last_word_ptr;
while (to <= end)
*to++ ^= 0xFFFFFFFF;
- *map->last_word_ptr|= map->last_word_mask; /*Set last bits again*/
}
@@ -418,21 +465,35 @@ uint bitmap_bits_set(const MY_BITMAP *map)
uint res= 0;
DBUG_ASSERT(map->bitmap);
- *map->last_word_ptr^=map->last_word_mask; /*Reset last bits to zero*/
+ *map->last_word_ptr&= ~map->last_word_mask; /*Reset last bits to zero*/
while (m < end)
res+= my_count_bits_ushort(*m++);
- *map->last_word_ptr^=map->last_word_mask; /*Set last bits to one again*/
return res;
}
+
+void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
+{
+ my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
+
+ DBUG_ASSERT(map->bitmap && map2->bitmap &&
+ map->n_bits==map2->n_bits);
+ end= map->last_word_ptr;
+ while (to <= end)
+ *to++ = *from++;
+}
+
+
uint bitmap_get_first_set(const MY_BITMAP *map)
{
uchar *byte_ptr;
- uint bit_found,i,j,k;
- uint32 *data_ptr, *end= map->last_word_ptr;
+ uint i,j,k;
+ my_bitmap_map *data_ptr, *end= map->last_word_ptr;
DBUG_ASSERT(map->bitmap);
data_ptr= map->bitmap;
+ *map->last_word_ptr &= ~map->last_word_mask;
+
for (i=0; data_ptr <= end; data_ptr++, i++)
{
if (*data_ptr)
@@ -445,12 +506,7 @@ uint bitmap_get_first_set(const MY_BITMAP *map)
for (k=0; ; k++)
{
if (*byte_ptr & (1 << k))
- {
- bit_found= (i*32) + (j*8) + k;
- if (bit_found == map->n_bits)
- return MY_BIT_NONE;
- return bit_found;
- }
+ return (i*32) + (j*8) + k;
}
DBUG_ASSERT(0);
}
@@ -465,11 +521,13 @@ uint bitmap_get_first_set(const MY_BITMAP *map)
uint bitmap_get_first(const MY_BITMAP *map)
{
uchar *byte_ptr;
- uint bit_found= MY_BIT_NONE, i,j,k;
- uint32 *data_ptr, *end= map->last_word_ptr;
+ uint i,j,k;
+ my_bitmap_map *data_ptr, *end= map->last_word_ptr;
DBUG_ASSERT(map->bitmap);
data_ptr= map->bitmap;
+ *map->last_word_ptr|= map->last_word_mask;
+
for (i=0; data_ptr <= end; data_ptr++, i++)
{
if (*data_ptr != 0xFFFFFFFF)
@@ -482,12 +540,7 @@ uint bitmap_get_first(const MY_BITMAP *map)
for (k=0; ; k++)
{
if (!(*byte_ptr & (1 << k)))
- {
- bit_found= (i*32) + (j*8) + k;
- if (bit_found == map->n_bits)
- return MY_BIT_NONE;
- return bit_found;
- }
+ return (i*32) + (j*8) + k;
}
DBUG_ASSERT(0);
}
@@ -705,16 +758,6 @@ void bitmap_lock_flip_bit(MY_BITMAP *map, uint bitmap_bit)
#endif
#ifdef MAIN
-static void bitmap_print(MY_BITMAP *map)
-{
- uint32 *to= map->bitmap, *end= map->last_word_ptr;
- while (to <= end)
- {
- fprintf(stderr,"0x%x ", *to++);
- }
- fprintf(stderr,"\n");
-}
-
uint get_rand_bit(uint bitsize)
{
return (rand() % bitsize);
@@ -766,7 +809,8 @@ error2:
return TRUE;
}
-bool test_operators(MY_BITMAP *map, uint bitsize)
+bool test_operators(MY_BITMAP *map __attribute__((unused)),
+ uint bitsize __attribute__((unused)))
{
return FALSE;
}
@@ -819,8 +863,8 @@ bool test_compare_operators(MY_BITMAP *map, uint bitsize)
uint no_loops= bitsize > 128 ? 128 : bitsize;
MY_BITMAP map2_obj, map3_obj;
MY_BITMAP *map2= &map2_obj, *map3= &map3_obj;
- uint32 map2buf[1024];
- uint32 map3buf[1024];
+ my_bitmap_map map2buf[1024];
+ my_bitmap_map map3buf[1024];
bitmap_init(&map2_obj, map2buf, bitsize, FALSE);
bitmap_init(&map3_obj, map3buf, bitsize, FALSE);
bitmap_clear_all(map2);
@@ -947,7 +991,7 @@ error2:
bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
{
- uint i, j, test_bit;
+ uint i, test_bit;
uint no_loops= bitsize > 128 ? 128 : bitsize;
for (i=0; i < no_loops; i++)
{
@@ -1027,7 +1071,7 @@ error3:
bool do_test(uint bitsize)
{
MY_BITMAP map;
- uint32 buf[1024];
+ my_bitmap_map buf[1024];
if (bitmap_init(&map, buf, bitsize, FALSE))
{
printf("init error for bitsize %d", bitsize);
diff --git a/mysys/my_clock.c b/mysys/my_clock.c
index decb9902e8c..70bb374a749 100644
--- a/mysys/my_clock.c
+++ b/mysys/my_clock.c
@@ -23,7 +23,7 @@
long my_clock(void)
{
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
struct tms tmsbuf;
VOID(times(&tmsbuf));
return (tmsbuf.tms_utime + tmsbuf.tms_stime);
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 1bf024c524f..2233c791153 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -94,7 +94,7 @@ int my_copy(const char *from, const char *to, myf MyFlags)
if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
DBUG_RETURN(0); /* File copyed but not stat */
VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
VOID(chown(to, stat_buff.st_uid,stat_buff.st_gid)); /* Copy ownership */
#endif
#if !defined(VMS) && !defined(__ZTC__)
diff --git a/mysys/my_create.c b/mysys/my_create.c
index bb5b2f2be61..e1e32b50842 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -18,7 +18,7 @@
#include <my_dir.h>
#include "mysys_err.h"
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#include <share.h>
#endif
@@ -46,13 +46,6 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
#elif defined(VMS)
fd = open((my_string) FileName, access_flags | O_CREAT, 0,
"ctx=stm","ctx=bin");
-#elif defined(MSDOS)
- if (access_flags & O_SHARE)
- fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
- SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
- else
- fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
- MY_S_IREAD | MY_S_IWRITE);
#elif defined(__WIN__)
fd= my_sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
diff --git a/mysys/my_dup.c b/mysys/my_dup.c
index 55f22931cd4..1fdb4db7276 100644
--- a/mysys/my_dup.c
+++ b/mysys/my_dup.c
@@ -18,7 +18,7 @@
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#include <share.h>
#endif
diff --git a/mysys/my_gethostbyname.c b/mysys/my_gethostbyname.c
index 27281f3489d..0644ba02bbd 100644
--- a/mysys/my_gethostbyname.c
+++ b/mysys/my_gethostbyname.c
@@ -18,7 +18,7 @@
/* Thread safe version of gethostbyname_r() */
#include "mysys_priv.h"
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <netdb.h>
#endif
#include <my_net.h>
diff --git a/mysys/my_getncpus.c b/mysys/my_getncpus.c
new file mode 100644
index 00000000000..6c45617e496
--- /dev/null
+++ b/mysys/my_getncpus.c
@@ -0,0 +1,40 @@
+/* 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 */
+
+/* get the number of (online) CPUs */
+
+#include "mysys_priv.h"
+#include <unistd.h>
+
+static int ncpus=0;
+
+#ifdef _SC_NPROCESSORS_ONLN
+int my_getncpus()
+{
+ if (!ncpus)
+ ncpus= sysconf(_SC_NPROCESSORS_ONLN);
+ return ncpus;
+}
+
+#else
+/* unknown */
+int my_getncpus()
+{
+ return 2;
+}
+
+#endif
+
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 95dc5afeae9..4de2984d9b9 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -486,7 +486,7 @@ invalid value '%s'\n",
}
get_one_option(optp->id, optp, argument);
- (*argc)--; /* option handled (short or long), decrease argument count */
+ (*argc)--; /* option handled (short or long), decrease argument count */
}
else /* non-option found */
(*argv)[argvpos++]= cur_arg;
diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c
index 765c30bc281..de8ad108ba4 100644
--- a/mysys/my_getwd.c
+++ b/mysys/my_getwd.c
@@ -22,7 +22,7 @@
#ifdef HAVE_GETWD
#include <sys/param.h>
#endif
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#include <m_ctype.h>
#include <dos.h>
#include <direct.h>
@@ -39,11 +39,9 @@ int my_getwd(my_string buf, uint size, myf MyFlags)
DBUG_ENTER("my_getwd");
DBUG_PRINT("my",("buf: 0x%lx size: %d MyFlags %d", buf,size,MyFlags));
-#if ! defined(MSDOS)
if (curr_dir[0]) /* Current pos is saved here */
VOID(strmake(buf,&curr_dir[0],size-1));
else
-#endif
{
#if defined(HAVE_GETCWD)
if (!getcwd(buf,size-2) && MyFlags & MY_WME)
@@ -87,43 +85,13 @@ int my_setwd(const char *dir, myf MyFlags)
int res;
size_s length;
my_string start,pos;
-#if defined(VMS) || defined(MSDOS)
+#if defined(VMS)
char buff[FN_REFLEN];
#endif
DBUG_ENTER("my_setwd");
DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
start=(my_string) dir;
-#if defined(MSDOS) /* MSDOS chdir can't change drive */
-#if !defined(_DDL) && !defined(WIN32)
- if ((pos=(char*) strchr(dir,FN_DEVCHAR)) != 0)
- {
- uint drive,drives;
-
- pos++; /* Skip FN_DEVCHAR */
- drive=(uint) (my_toupper(&my_charset_latin1,dir[0])-'A'+1);
- drives= (uint) -1;
- if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
- {
- _dos_setdrive(drive,&drives);
- _dos_getdrive(&drives);
- }
- if (drive != drives)
- {
- *pos='\0'; /* Dir is now only drive */
- my_errno=errno;
- my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
- DBUG_RETURN(-1);
- }
- dir=pos; /* drive changed, change now path */
- }
-#endif
- if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
- {
- strmov(buff,dir)[-1]=0; /* Remove last '/' */
- dir=buff;
- }
-#endif /* MSDOS*/
if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
dir=FN_ROOTDIR;
#ifdef VMS
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 9efe0a0c20e..588bb6f46d6 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -181,7 +181,7 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
rus.ru_nvcsw, rus.ru_nivcsw);
#endif
-#if ( defined(MSDOS) || defined(__NETWARE__) ) && !defined(__WIN__)
+#if defined(__NETWARE__) && !defined(__WIN__)
fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
#endif
#if defined(SAFEMALLOC)
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
index 12cc64d0ad9..4ed44b0573f 100644
--- a/mysys/my_lib.c
+++ b/mysys/my_lib.c
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* TODO: check for overun of memory for names. */
-/* Convert MSDOS-TIME to standar time_t */
+/* Convert MSDOS-TIME to standar time_t (still needed?) */
#include "mysys_priv.h"
#include <m_string.h>
@@ -36,7 +36,7 @@
# if defined(HAVE_NDIR_H)
# include <ndir.h>
# endif
-# if defined(MSDOS) || defined(__WIN__)
+# if defined(__WIN__)
# include <dos.h>
# ifdef __BORLANDC__
# include <dir.h>
@@ -93,7 +93,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
} /* comp_names */
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
MY_DIR *my_dir(const char *path, myf MyFlags)
{
@@ -346,7 +346,7 @@ my_string directory_file_name (my_string dst, const char *src)
#endif /* VMS */
} /* directory_file_name */
-#elif defined(WIN32)
+#else
/*
*****************************************************************************
@@ -385,7 +385,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
*tmp_file++= '.'; /* From current dev-dir */
if (tmp_file[-1] != FN_LIBCHAR)
*tmp_file++ =FN_LIBCHAR;
- tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[0]='*'; /* Windows needs this !??? */
tmp_file[1]='.';
tmp_file[2]='*';
tmp_file[3]='\0';
@@ -508,109 +508,7 @@ error:
DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
-#else /* MSDOS and not WIN32 */
-
-
-/******************************************************************************
-** At MSDOS you always get stat of files, but time is in packed MSDOS-format
-******************************************************************************/
-
-MY_DIR *my_dir(const char* path, myf MyFlags)
-{
- char *buffer;
- MY_DIR *result= 0;
- FILEINFO finfo;
- DYNAMIC_ARRAY *dir_entries_storage;
- MEM_ROOT *names_storage;
- struct find_t find;
- ushort mode;
- char tmp_path[FN_REFLEN],*tmp_file,attrib;
- DBUG_ENTER("my_dir");
- DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
-
- /* Put LIB-CHAR as last path-character if not there */
-
- tmp_file=tmp_path;
- if (!*path)
- *tmp_file++ ='.'; /* From current dir */
- tmp_file= strmov(tmp_file,path);
- if (tmp_file[-1] == FN_DEVCHAR)
- *tmp_file++= '.'; /* From current dev-dir */
- if (tmp_file[-1] != FN_LIBCHAR)
- *tmp_file++ =FN_LIBCHAR;
- tmp_file[0]='*'; /* MSDOS needs this !??? */
- tmp_file[1]='.';
- tmp_file[2]='*';
- tmp_file[3]='\0';
-
- if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
- goto error;
-
- if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
- ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
- sizeof(MEM_ROOT), MyFlags)))
- goto error;
-
- dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
- names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
- ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
-
- if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
- ENTRIES_START_SIZE, ENTRIES_INCREMENT))
- {
- my_free((gptr) buffer,MYF(0));
- goto error;
- }
- init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
-
- /* MY_DIR structure is allocated and completly initialized at this point */
- result= (MY_DIR*)buffer;
-
- do
- {
- if (!(finfo.name= strdup_root(names_storage, find.name)))
- goto error;
-
- if (MyFlags & MY_WANT_STAT)
- {
- if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
- sizeof(MY_STAT))))
- goto error;
-
- bzero(finfo.mystat, sizeof(MY_STAT));
- finfo.mystat->st_size= find.size;
- mode= MY_S_IREAD; attrib= find.attrib;
- if (!(attrib & _A_RDONLY))
- mode|= MY_S_IWRITE;
- if (attrib & _A_SUBDIR)
- mode|= MY_S_IFDIR;
- finfo.mystat->st_mode= mode;
- finfo.mystat->st_mtime= ((uint32) find.wr_date << 16) + find.wr_time;
- }
- else
- finfo.mystat= NULL;
-
- if (push_dynamic(dir_entries_storage, (gptr)&finfo))
- goto error;
-
- } while (_dos_findnext(&find) == 0);
-
- result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
- result->number_off_files= dir_entries_storage->elements;
-
- if (!(MyFlags & MY_DONT_SORT))
- qsort((void *) result->dir_entry, result->number_off_files,
- sizeof(FILEINFO), (qsort_cmp) comp_names);
- DBUG_RETURN(result);
-
-error:
- my_dirend(result);
- if (MyFlags & MY_FAE+MY_WME)
- my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
- DBUG_RETURN((MY_DIR *) NULL);
-} /* my_dir */
-
-#endif /* WIN32 && MSDOS */
+#endif /* __WIN__ */
/****************************************************************************
** File status
diff --git a/mysys/my_net.c b/mysys/my_net.c
index be92adae353..09c09b280d1 100644
--- a/mysys/my_net.c
+++ b/mysys/my_net.c
@@ -20,7 +20,7 @@
#include <m_string.h>
/* for thread safe my_inet_ntoa */
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <netdb.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -31,7 +31,7 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#endif /* !defined(MSDOS) && !defined(__WIN__) */
+#endif /* !defined(__WIN__) */
void my_inet_ntoa(struct in_addr in, char *buf)
{
diff --git a/mysys/my_open.c b/mysys/my_open.c
index b070258505a..6e57132ae23 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -18,7 +18,7 @@
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#include <share.h>
#endif
@@ -44,7 +44,7 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
DBUG_ENTER("my_open");
DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
FileName, Flags, MyFlags));
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
/*
Check that we don't try to open or create a file name that may
cause problems for us in the future (like PRN)
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
index 9a1149e6f88..7782190ae11 100644
--- a/mysys/my_redel.c
+++ b/mysys/my_redel.c
@@ -89,14 +89,14 @@ int my_copystat(const char *from, const char *to, int MyFlags)
return 1;
VOID(chmod(to, statbuf.st_mode & 07777)); /* Copy modes */
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING)
{
if (MyFlags & MY_LINK_WARNING)
my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink);
}
VOID(chown(to, statbuf.st_uid, statbuf.st_gid)); /* Copy ownership */
-#endif /* MSDOS */
+#endif /* !__WIN__ && !__NETWARE__ */
#ifndef VMS
#ifndef __ZTC__
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 4b3e03750c8..b4de57229bf 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -480,7 +480,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
data->type=lock_type;
data->owner= owner; /* Must be reset ! */
VOID(pthread_mutex_lock(&lock->mutex));
- DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx type: %d",
+ DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
data, data->owner->info->thread_id,
lock, (int) lock_type));
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
@@ -499,7 +499,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
and the read lock is not TL_READ_NO_INSERT
*/
- DBUG_PRINT("lock",("write locked by thread: %ld",
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx",
lock->write.data->owner->info->thread_id));
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
(lock->write.data->type <= TL_WRITE_DELAYED &&
@@ -621,7 +621,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
- DBUG_PRINT("lock",("write locked by thread: %ld",
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx",
lock->write.data->owner->info->thread_id));
}
else
@@ -657,7 +657,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
goto end;
}
}
- DBUG_PRINT("lock",("write locked by thread: %ld, type: %ld",
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx, type: %ld",
lock->read.data->owner->info->thread_id, data->type));
}
wait_queue= &lock->write_wait;
@@ -719,7 +719,7 @@ static inline void free_all_read_locks(THR_LOCK *lock,
}
lock->read_no_write_count++;
}
- DBUG_PRINT("lock",("giving read lock to thread: %ld",
+ DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
data->owner->info->thread_id));
data->cond=0; /* Mark thread free */
VOID(pthread_cond_signal(cond));
@@ -737,7 +737,7 @@ void thr_unlock(THR_LOCK_DATA *data)
THR_LOCK *lock=data->lock;
enum thr_lock_type lock_type=data->type;
DBUG_ENTER("thr_unlock");
- DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx",
+ DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
data, data->owner->info->thread_id, lock));
pthread_mutex_lock(&lock->mutex);
check_locks(lock,"start of release lock",0);
@@ -797,7 +797,7 @@ void thr_unlock(THR_LOCK_DATA *data)
if (data->type == TL_WRITE_CONCURRENT_INSERT &&
(*lock->check_status)(data->status_param))
data->type=TL_WRITE; /* Upgrade lock */
- DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld",
+ DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%lx",
data->type, data->owner->info->thread_id));
{
pthread_cond_t *cond=data->cond;
diff --git a/plugin/fulltext/Makefile.am b/plugin/fulltext/Makefile.am
index 4df5a1dc78a..7b4ae22cbd2 100644
--- a/plugin/fulltext/Makefile.am
+++ b/plugin/fulltext/Makefile.am
@@ -6,4 +6,4 @@ noinst_LTLIBRARIES= mypluglib.la
#pkglib_LTLIBRARIES= mypluglib.la
mypluglib_la_SOURCES= plugin_example.c
mypluglib_la_LDFLAGS= -module -rpath $(pkglibdir)
-
+mypluglib_la_CFLAGS= -DMYSQL_DYNAMIC_PLUGIN
diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c
index 9b937453ce4..eefb10bd26b 100644
--- a/plugin/fulltext/plugin_example.c
+++ b/plugin/fulltext/plugin_example.c
@@ -144,10 +144,7 @@ static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len)
MYSQL_FTPARSER_BOOLEAN_INFO bool_info=
{ FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 };
- if (param->mode == MYSQL_FTPARSER_FULL_BOOLEAN_INFO)
- param->mysql_add_word(param->mysql_ftparam, word, len, &bool_info);
- else
- param->mysql_add_word(param->mysql_ftparam, word, len, 0);
+ param->mysql_add_word(param, word, len, &bool_info);
}
/*
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 56a2d4a7bc6..af3cbc19cb5 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -30,7 +30,6 @@ bin_SCRIPTS = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
- mysql_explain_log \
mysqld_multi \
mysql_create_system_tables
@@ -55,7 +54,6 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \
mysql_find_rows.sh \
mysqlhotcopy.sh \
mysqldumpslow.sh \
- mysql_explain_log.sh \
mysqld_multi.sh \
mysqld_safe.sh \
mysql_create_system_tables.sh
@@ -83,7 +81,6 @@ CLEANFILES = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
- mysql_explain_log \
mysql_tableinfo \
mysqld_multi \
make_win_src_distribution \
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index aa29d48d50d..1b071a294ed 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -148,7 +148,7 @@ BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \
if [ $BASE_SYSTEM = "netware" ] ; then
BIN_FILES="$BIN_FILES \
netware/mysqld_safe$BS netware/mysql_install_db$BS \
- netware/init_db.sql netware/test_db.sql netware/mysql_explain_log$BS \
+ netware/init_db.sql netware/test_db.sql$BS \
netware/mysqlhotcopy$BS netware/libmysql$BS netware/init_secure_db.sql \
";
# For all other platforms:
diff --git a/scripts/make_sharedlib_distribution.sh b/scripts/make_sharedlib_distribution.sh
index fbc945e445a..c475d0e14a4 100644
--- a/scripts/make_sharedlib_distribution.sh
+++ b/scripts/make_sharedlib_distribution.sh
@@ -45,9 +45,11 @@ fi
mkdir -p $BASE/lib
for i in \
- libmysql/.libs/libmysqlclient.s{l,o}* \
+ libmysql/.libs/libmysqlclient.so* \
+ libmysql/.libs/libmysqlclient.sl* \
libmysql/.libs/libmysqlclient*.dylib \
- libmysql_r/.libs/libmysqlclient_r.s{l,o}* \
+ libmysql_r/.libs/libmysqlclient_r.so* \
+ libmysql_r/.libs/libmysqlclient_r.sl* \
libmysql_r/.libs/libmysqlclient_r*.dylib
do
if [ -f $i ]
diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh
index b070e30c5c7..6883719cbe4 100644
--- a/scripts/make_win_src_distribution.sh
+++ b/scripts/make_win_src_distribution.sh
@@ -343,6 +343,7 @@ mv $BASE/sql/sql_yacc.cpp-new $BASE/sql/sql_yacc.cpp
find $BASE \( -name "*.cnf" -o -name "*.ini" \
-o -name COPYING -o -name ChangeLog -o -name EXCEPTIONS-CLIENT \
-o -name "INSTALL*" -o -name LICENSE -o -name "README*" \
+ -o -name "*.dsp" -o -name "*.dsw" \
-o -name "*.vcproj" -o -name "*.sln" \) -type f -print \
| while read v
do
diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh
index a401e1d0159..69ea8e3d004 100644
--- a/scripts/mysql_create_system_tables.sh
+++ b/scripts/mysql_create_system_tables.sh
@@ -827,7 +827,7 @@ then
c_ev="$c_ev 'HIGH_NOT_PRECEDENCE'"
c_ev="$c_ev ) DEFAULT '' NOT NULL,"
c_ev="$c_ev comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',"
- c_ev="$c_ev PRIMARY KEY (definer, db, name)"
+ c_ev="$c_ev PRIMARY KEY (db, name)"
c_ev="$c_ev ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';"
fi
diff --git a/scripts/mysql_explain_log.sh b/scripts/mysql_explain_log.sh
deleted file mode 100644
index 973d9e8a363..00000000000
--- a/scripts/mysql_explain_log.sh
+++ /dev/null
@@ -1,392 +0,0 @@
-#!@PERL@ -w
-use strict;
-use DBI;
-
-use Getopt::Long;
-$Getopt::Long::ignorecase=0;
-
-print "explain_log provided by http://www.mobile.de\n";
-print "=========== ================================\n";
-
-my $Param={};
-
-$Param->{host}='';
-$Param->{user}='';
-$Param->{password}='';
-$Param->{PrintError}=0;
-$Param->{socket}='';
-
-if (!GetOptions ('date|d:i' => \$Param->{ViewDate},
- 'host|h:s' => \$Param->{host},
- 'user|u:s' => \$Param->{user},
- 'password|p:s' => \$Param->{password},
- 'printerror|e:s' => \$Param->{PrintError},
- 'socket|s:s' => \$Param->{socket},
- )) {
- ShowOptions();
-}
-else {
- $Param->{UpdateCount} = 0;
- $Param->{SelectCount} = 0;
- $Param->{IdxUseCount} = 0;
- $Param->{LineCount} = 0;
-
- $Param->{Init} = 0;
- $Param->{Field} = 0;
- $Param->{Refresh} = 0;
- $Param->{QueryCount} = 0;
- $Param->{Statistics} =0;
-
- $Param->{Query} = undef;
- $Param->{ALL} = undef ;
- $Param->{Comment} = undef ;
-
- @{$Param->{Rows}} = (qw|possible_keys key type|);
-
- if ($Param->{ViewDate}) {
- $Param->{View} = 0;
- }
- else {
- $Param->{View} = 1;
- }
-
- #print "Date=$Param->{ViewDate}, host=$Param->{host}, user=$Param->{user}, password=$Param->{password}\n";
-
- $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}".($Param->{socket}?";mysql_socket=$Param->{socket}":""),$Param->{user},$Param->{password},{PrintError=>0});
- if (DBI::err()) {
- print "Error: " . DBI::errstr() . "\n";
- }
- else {
- $Param->{Start} = time;
- while(<STDIN>) {
- $Param->{LineCount} ++ ;
-
- if ($Param->{ViewDate} ) {
- if (m/^(\d{6})\s+\d{1,2}:\d\d:\d\d\s.*$/) { # get date
- #print "# $1 #\n";
- if ($1 == $Param->{ViewDate}) {
- $Param->{View} = 1;
- }
- else {
- $Param->{View} = 0;
- }
- }
- }
- if ($Param->{View} ) {
- #print "->>>$_";
-
- if (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
- #print "C-$1--$2--$3------\n";
- RunQuery($Param);
- if (defined $3) {
- $Param->{CID}->{$2} = $3 ;
- #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
- }
- }
-
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+$/i) { # get connection ID($2) and database($3)
- #print "\n <<<<<<<<<<<<<<<<<<----------------------------<<<<<<<<<<<<<<<< \n";
- #print "Connect \n";
- RunQuery($Param);
- }
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Change user .*\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
- #print "C-$1--$2--$3------\n";
- RunQuery($Param);
- if (defined $3) {
- $Param->{CID}->{$2} = $3 ;
- #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
- }
- }
-
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Quit\s+$/i) { # remove connection ID($2) and querystring
- #print "Q-$1--$2--------\n";
- RunQuery($Param);
- delete $Param->{CID}->{$2} ;
- }
-
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(select.+)$/i) { # get connection ID($2) and querystring
- #print "S1-$1--$2--$3------\n";
- RunQuery($Param);
- unless ($Param->{CID}->{$2}) {
- #print "Error: No Database for Handle: $2 found\n";
- }
- else {
- $Param->{DB}=$Param->{CID}->{$2};
-
- my $s = "$3";
- $s =~ s/from\s/from $Param->{DB}./i;
- $Param->{Query}="EXPLAIN $s";
-
- #$s =~ m/from\s+(\w+[.]\w+)/i;
- #$Param->{tab} =$1;
- #print "-- $Param->{tab} -- $s --\n";
- }
- }
-
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(update.+)$/i) { # get connection ID($2) and querystring
- #print "S2--$1--$2--$3------\n";
- RunQuery($Param);
- unless ($Param->{CID}->{$2}) {
- #print "Error: No Database for Handle: $2 found\n";
- }
- else {
- $Param->{DB}=$Param->{CID}->{$2};
-
- my $ud = $3;
- $ud =~ m/^update\s+(\w+).+(where.+)$/i;
- $Param->{Query} ="EXPLAIN SELECT * FROM $1 $2";
- $Param->{Query} =~ s/from\s/from $Param->{DB}./i;
-
- #$Param->{Query} =~ m/from\s+(\w+[.]\w+)/i;
- #$Param->{tab} =$1;
- }
- }
-
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Statistics\s+(.*)$/i) { # get connection ID($2) and info?
- $Param->{Statistics} ++;
- #print "Statistics--$1--$2--$3------\n";
- RunQuery($Param);
- }
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(.+)$/i) { # get connection ID($2)
- $Param->{QueryCount} ++;
- #print "Query-NULL $3\n";
- RunQuery($Param);
- }
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Refresh\s+(.+)$/i) { # get connection ID($2)
- $Param->{Refresh} ++;
- #print "Refresh\n";
- RunQuery($Param);
- }
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Init\s+(.+)$/i) { # get connection ID($2)
- $Param->{Init} ++;
- #print "Init $3\n";
- RunQuery($Param);
- }
- elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Field\s+(.+)$/i) { # get connection ID($2)
- $Param->{Field} ++;
- #print "Field $3\n";
- RunQuery($Param);
- }
-
- elsif (m/^\s+(.+)$/ ) { # command could be some lines ...
- #print "multi-lined ($1)\n";
- my ($A)=$1;
- chomp $A;
- $Param->{Query} .= " $1";
- #print "multi-lined ($1)<<$Param->{Query}>>\n";
- }
-
-
- }
-
- }
-
- $Param->{dbh}->disconnect();
-
- if (1 == 0) {
- print "\nunclosed handles----------------------------------------\n";
- my $count=0;
- foreach (sort keys %{$Param->{CID}}) {
- print "$count | $_ : $Param->{CID}->{$_} \n";
- $count ++;
- }
- }
-
- print "\nIndex usage ------------------------------------\n";
- foreach my $t (sort keys %{$Param->{Data}}) {
- print "\nTable\t$t: ---\n";
- foreach my $k (sort keys %{$Param->{Data}->{$t}}) {
- print " count\t$k:\n";
- my %h = %{$Param->{Data}->{$t}->{$k}};
- foreach (sort {$h{$a} <=> $h{$b}} keys %h) {
- print " $Param->{Data}->{$t}->{$k}->{$_}\t$_\n";
- }
- }
- }
-
- $Param->{AllCount}=0;
- print "\nQueries causing table scans -------------------\n\n";
- foreach (@{$Param->{ALL}}) {
- $Param->{AllCount} ++;
- print "$_\n";
- }
- print "Sum: $Param->{AllCount} table scans\n";
-
- print "\nSummary ---------------------------------------\n\n";
- print "Select: \t$Param->{SelectCount} queries\n";
- print "Update: \t$Param->{UpdateCount} queries\n";
- print "\n";
-
- print "Init: \t$Param->{Init} times\n";
- print "Field: \t$Param->{Field} times\n";
- print "Refresh: \t$Param->{Refresh} times\n";
- print "Query: \t$Param->{QueryCount} times\n";
- print "Statistics:\t$Param->{Statistics} times\n";
- print "\n";
-
- print "Logfile: \t$Param->{LineCount} lines\n";
- print "Started: \t".localtime($Param->{Start})."\n";
- print "Finished: \t".localtime(time)."\n";
-
- }
-}
-
-
-###########################################################################
-#
-#
-#
-sub RunQuery {
- my $Param = shift ;
-
- if (defined $Param->{Query}) {
- if (defined $Param->{DB} ) {
-
- $Param->{Query} =~ m/from\s+(\w+[.]\w+|\w+)/i;
- $Param->{tab} =$1;
- #print "||$Param->{tab} -- $Param->{Query}\n";
-
- my $sth=$Param->{dbh}->prepare("USE $Param->{DB}");
- if (DBI::err()) {
- if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
- }
- else {
- $sth->execute();
- if (DBI::err()) {
- if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
- }
- else {
- $sth->finish();
-
- $sth=$Param->{dbh}->prepare($Param->{Query});
- if (DBI::err()) {
- if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
- }
- else {
- #print "$Param->{Query}\n";
- $sth->execute();
- if (DBI::err()) {
- if ($Param->{PrintError}) {print "[$Param->{LineCount}]<<$Param->{Query}>>\n";}
- if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
- }
- else {
- my $row = undef;
- while ($row = $sth->fetchrow_hashref()) {
- $Param->{SelectCount} ++;
-
- if (defined $row->{Comment}) {
- push (@{$Param->{Comment}}, "$row->{Comment}; $_; $Param->{DB}; $Param->{Query}");
- }
- foreach (@{$Param->{Rows}}) {
- if (defined $row->{$_}) {
- #if (($_ eq 'type' ) and ($row->{$_} eq 'ALL')) {
- if ($row->{type} eq 'ALL') {
- push (@{$Param->{ALL}}, "$Param->{Query}");
- #print ">> $row->{$_} $_ $Param->{DB} $Param->{Query}\n";
- }
- $Param->{IdxUseCount} ++;
- $Param->{Data}->{$Param->{tab}}->{$_}->{$row->{$_}} ++;
- }
- }
- }
- }
- }
- }
- }
- $sth->finish();
- }
- $Param->{Query} = undef ;
- }
-}
-
-###########################################################################
-#
-#
-#
-sub ShowOptions {
- print <<EOF;
-Usage: $0 [OPTIONS] < LOGFILE
-
---date=YYMMDD select only entrys of date
--d=YYMMDD
---host=HOSTNAME db-host to ask
--h=HOSTNAME
---user=USERNAME db-user
--u=USERNAME
---password=PASSWORD password of db-user
--p=PASSWORD
---socket=SOCKET mysqld socket file to connect
--s=SOCKET
-
-Read logfile from STDIN an try to EXPLAIN all SELECT statements. All UPDATE statements are rewritten to an EXPLAIN SELECT statement. The results of the EXPLAIN statement are collected and counted. All results with type=ALL are collected in an separete list. Results are printed to STDOUT.
-
-EOF
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
-explain_log.pl
-
-Feed a mysqld general logfile (created with mysqld --log) back into mysql
-and collect statistics about index usage with EXPLAIN.
-
-=head1 DISCUSSION
-
-To optimize your indices, you have to know which ones are actually
-used and what kind of queries are causing table scans. Especially
-if you are generating your queries dynamically and you have a huge
-amount of queries going on, this isn't easy.
-
-Use this tool to take a look at the effects of your real life queries.
-Then add indices to avoid table scans and remove those which aren't used.
-
-=head1 USAGE
-
-explain_log.pl [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] [--socket=/path/to/socket] < logfile
-
---date=YYMMDD select only entrys of date
-
--d=YYMMDD
-
---host=HOSTNAME db-host to ask
-
--h=HOSTNAME
-
---user=USERNAME db-user
-
--u=USERNAME
-
---password=PASSWORD password of db-user
-
--p=PASSWORD
-
---socket=SOCKET change path to the socket
-
--s=SOCKET
-
-=head1 EXAMPLE
-
-explain_log.pl --host=localhost --user=foo --password=bar < /var/lib/mysql/mobile.log
-
-=head1 AUTHORS
-
- Stefan Nitz
- Jan Willamowius <jan@mobile.de>, http://www.mobile.de
- Dennis Haney <davh@davh.dk> (Added socket support)
-
-=head1 RECRUITING
-
-If you are looking for a MySQL or Perl job, take a look at http://www.mobile.de
-and send me an email with your resume (you must be speaking German!).
-
-=head1 SEE ALSO
-
-mysql documentation
-
-=cut
diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql
index 5b3cab16db2..f3c0c7f13be 100644
--- a/scripts/mysql_fix_privilege_tables.sql
+++ b/scripts/mysql_fix_privilege_tables.sql
@@ -570,7 +570,7 @@ DROP PROCEDURE create_log_tables;
CREATE TABLE event (
db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- name char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
+ name char(64) CHARACTER SET utf8 NOT NULL default '',
body longblob NOT NULL,
definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
execute_at DATETIME default NULL,
@@ -636,7 +636,7 @@ SELECT @hadEventPriv :=1 FROM user WHERE Event_priv LIKE '%';
ALTER TABLE user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv;
ALTER TABLE db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL;
ALTER TABLE event DROP PRIMARY KEY;
-ALTER TABLE event ADD PRIMARY KEY(definer, db, name);
+ALTER TABLE event ADD PRIMARY KEY(db, name);
ALTER TABLE event ADD sql_mode
set('REAL_AS_FLOAT',
'PIPES_AS_CONCAT',
diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt
index c20b9c7f9df..1983d459ce2 100644
--- a/server-tools/instance-manager/CMakeLists.txt
+++ b/server-tools/instance-manager/CMakeLists.txt
@@ -9,6 +9,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
../../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/IMService.cpp b/server-tools/instance-manager/IMService.cpp
index b7ea8e7eb81..f9ea7ee471d 100644
--- a/server-tools/instance-manager/IMService.cpp
+++ b/server-tools/instance-manager/IMService.cpp
@@ -20,7 +20,7 @@ IMService::~IMService(void)
void IMService::Stop()
{
ReportStatus(SERVICE_STOP_PENDING);
-
+
// stop the IM work
raise(SIGTERM);
}
@@ -30,15 +30,14 @@ void IMService::Run(DWORD argc, LPTSTR *argv)
// report to the SCM that we're about to start
ReportStatus((DWORD)SERVICE_START_PENDING);
- Options o;
- o.load(argc, argv);
-
+ Options::load(argc, argv);
+
// init goes here
ReportStatus((DWORD)SERVICE_RUNNING);
// wait for main loop to terminate
- manager(o);
- o.cleanup();
+ manager();
+ Options::cleanup();
}
void IMService::Log(const char *msg)
@@ -46,13 +45,13 @@ void IMService::Log(const char *msg)
log_info(msg);
}
-int HandleServiceOptions(Options options)
+int HandleServiceOptions()
{
int ret_val= 0;
IMService winService;
- if (options.install_as_service)
+ if (Options::Service::install_as_service)
{
if (winService.IsInstalled())
log_info("Service is already installed");
@@ -64,7 +63,7 @@ int HandleServiceOptions(Options options)
ret_val= 1;
}
}
- else if (options.remove_service)
+ else if (Options::Service::remove_service)
{
if (! winService.IsInstalled())
log_info("Service is not installed");
@@ -77,6 +76,19 @@ int HandleServiceOptions(Options options)
}
}
else
- ret_val= !winService.Init();
+ {
+ log_info("Initializing Instance Manager service...");
+
+ if (!winService.Init())
+ {
+ log_info("Service failed to initialize.");
+ fprintf(stderr,
+ "The service should be started by Windows Service Manager.\n"
+ "The MySQL Manager should be started with '--standalone'\n"
+ "to run from command line.");
+ ret_val= 1;
+ }
+ }
+
return ret_val;
}
diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h
index cad38bebdaf..94d59c2af31 100644
--- a/server-tools/instance-manager/IMService.h
+++ b/server-tools/instance-manager/IMService.h
@@ -1,3 +1,21 @@
+/*
+ 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
+*/
+
#pragma once
#include "windowsservice.h"
@@ -12,3 +30,5 @@ protected:
void Stop();
void Run(DWORD argc, LPTSTR *argv);
};
+
+extern int HandleServiceOptions();
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
index 6ab5c3d1bfc..4719828081a 100644
--- a/server-tools/instance-manager/Makefile.am
+++ b/server-tools/instance-manager/Makefile.am
@@ -15,7 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES= @ZLIB_INCLUDES@ -I$(top_srcdir)/include \
- @openssl_includes@ @yassl_includes@ -I$(top_builddir)/include
+ @openssl_includes@ -I$(top_builddir)/include
DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER
@@ -76,7 +76,10 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
guardian.cc guardian.h \
parse_output.cc parse_output.h \
mysql_manager_error.h \
- portability.h
+ portability.h \
+ exit_codes.h \
+ user_management_commands.h \
+ user_management_commands.cc
mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \
liboptions.la \
diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp
index 192045b7a4c..8a36a2f2fdd 100644
--- a/server-tools/instance-manager/WindowsService.cpp
+++ b/server-tools/instance-manager/WindowsService.cpp
@@ -7,9 +7,9 @@ static WindowsService *gService;
WindowsService::WindowsService(void) :
statusCheckpoint(0),
serviceName(NULL),
- inited(false),
+ inited(FALSE),
dwAcceptedControls(SERVICE_ACCEPT_STOP),
- debugging(false)
+ debugging(FALSE)
{
gService= this;
status.dwServiceType= SERVICE_WIN32_OWN_PROCESS;
@@ -22,11 +22,12 @@ WindowsService::~WindowsService(void)
BOOL WindowsService::Install()
{
- bool ret_val= false;
+ bool ret_val= FALSE;
SC_HANDLE newService;
SC_HANDLE scm;
- if (IsInstalled()) return true;
+ if (IsInstalled())
+ return TRUE;
// determine the name of the currently executing file
char szFilePath[_MAX_PATH];
@@ -34,7 +35,7 @@ BOOL WindowsService::Install()
// open a connection to the SCM
if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
- return false;
+ return FALSE;
newService= CreateService(scm, serviceName, displayName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
@@ -45,7 +46,7 @@ BOOL WindowsService::Install()
if (newService)
{
CloseServiceHandle(newService);
- ret_val= true;
+ ret_val= TRUE;
}
CloseServiceHandle(scm);
@@ -56,34 +57,35 @@ BOOL WindowsService::Init()
{
assert(serviceName != NULL);
- if (inited) return true;
+ if (inited)
+ return TRUE;
SERVICE_TABLE_ENTRY stb[] =
{
{ (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{ NULL, NULL }
};
- inited= true;
+ inited= TRUE;
return StartServiceCtrlDispatcher(stb); //register with the Service Manager
}
BOOL WindowsService::Remove()
{
- bool ret_val= false;
+ bool ret_val= FALSE;
- if (! IsInstalled())
- return true;
+ if (!IsInstalled())
+ return TRUE;
// open a connection to the SCM
SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
- if (! scm)
- return false;
+ if (!scm)
+ return FALSE;
SC_HANDLE service= OpenService(scm, serviceName, DELETE);
if (service)
{
if (DeleteService(service))
- ret_val= true;
+ ret_val= TRUE;
DWORD dw= ::GetLastError();
CloseServiceHandle(service);
}
@@ -116,7 +118,8 @@ void WindowsService::SetAcceptedControls(DWORD acceptedControls)
BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint,
DWORD dwError)
{
- if(debugging) return TRUE;
+ if (debugging)
+ return TRUE;
if(currentState == SERVICE_START_PENDING)
status.dwControlsAccepted= 0;
diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h
index 1a034ce1351..3af7cdf39a7 100644
--- a/server-tools/instance-manager/WindowsService.h
+++ b/server-tools/instance-manager/WindowsService.h
@@ -1,3 +1,21 @@
+/*
+ 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
+*/
+
#pragma once
class WindowsService
diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h
index b84cc6a8e9e..f31ea404867 100644
--- a/server-tools/instance-manager/command.h
+++ b/server-tools/instance-manager/command.h
@@ -22,10 +22,12 @@
#pragma interface
#endif
-/* Class responsible for allocation of im commands. */
+/* Class responsible for allocation of IM commands. */
class Instance_map;
+struct st_net;
+
/*
Command - entry point for any command.
GangOf4: 'Command' design pattern
@@ -37,8 +39,18 @@ public:
Command(Instance_map *instance_map_arg= 0);
virtual ~Command();
- /* method of executing: */
- virtual int execute(struct st_net *net, ulong connection_id) = 0;
+ /*
+ This operation incapsulates behaviour of the command.
+
+ SYNOPSYS
+ net The network connection to the client.
+ connection_id Client connection ID
+
+ RETURN
+ 0 On success
+ non 0 On error. Client error code is returned.
+ */
+ virtual int execute(st_net *net, ulong connection_id) = 0;
protected:
Instance_map *instance_map;
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
index 7b999f61503..07e1e9a18f3 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -14,36 +14,53 @@
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(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
+#pragma implementation
+#endif
+
#include "commands.h"
+#include <my_global.h>
+#include <m_ctype.h>
+#include <mysql.h>
+#include <my_dir.h>
+
+#include "buffer.h"
+#include "guardian.h"
#include "instance_map.h"
+#include "log.h"
+#include "manager.h"
#include "messages.h"
#include "mysqld_error.h"
#include "mysql_manager_error.h"
-#include "protocol.h"
-#include "buffer.h"
#include "options.h"
+#include "priv.h"
+#include "protocol.h"
-#include <m_string.h>
-#include <m_ctype.h>
-#include <mysql.h>
-#include <my_dir.h>
+
+/*
+ modify_defaults_to_im_error -- a map of error codes of
+ mysys::modify_defaults_file() into Instance Manager error codes.
+*/
+
+static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
+ ER_ACCESS_OPTION_FILE };
/*
- Add a string to a buffer
+ Add a string to a buffer.
SYNOPSYS
put_to_buff()
buff buffer to add the string
str string to add
- uint offset in the buff to add a string
+ position offset in the buff to add a string
DESCRIPTION
Function to add a string to the buffer. It is different from
- store_to_protocol_packet, which is used in the protocol.cc. The last
- one also stores the length of the string in a special way.
+ store_to_protocol_packet, which is used in the protocol.cc.
+ The last one also stores the length of the string in a special way.
This is required for MySQL client/server protocol support only.
RETURN
@@ -51,7 +68,6 @@
1 - error occured
*/
-
static inline int put_to_buff(Buffer *buff, const char *str, uint *position)
{
uint len= strlen(str);
@@ -88,749 +104,1615 @@ static int parse_version_number(const char *version_str, char *version,
}
-/* implementation for Show_instances: */
+/**************************************************************************
+ Implementation of Instance_name.
+**************************************************************************/
+Instance_name::Instance_name(const LEX_STRING *name)
+{
+ str.str= str_buffer;
+ str.length= name->length;
-/*
- The method sends a list of instances in the instance map to the client.
+ if (str.length > MAX_INSTANCE_NAME_SIZE - 1)
+ str.length= MAX_INSTANCE_NAME_SIZE - 1;
- SYNOPSYS
- Show_instances::execute()
- net The network connection to the client.
- connection_id Client connection ID
+ strmake(str.str, name->str, str.length);
+}
- RETURN
- 0 - ok
- 1 - error occured
+/**************************************************************************
+ Implementation of Show_instances.
+**************************************************************************/
+
+/*
+ Implementation of SHOW INSTANCES statement.
+
+ Possible error codes:
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Show_instances::execute(struct st_net *net, ulong connection_id)
+int Show_instances::execute(st_net *net, ulong connection_id)
{
- Buffer send_buff; /* buffer for packets */
- LIST name, status;
- NAME_WITH_LENGTH name_field, status_field;
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net)))
+ return err_code;
+
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instances::write_header(st_net *net)
+{
+ LIST name, state;
+ LEX_STRING name_field, state_field;
LIST *field_list;
- uint position=0;
- name_field.name= (char*) "instance_name";
+ name_field.str= (char *) "instance_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- status_field.name= (char*) "status";
- status_field.length= DEFAULT_FIELD_LENGTH;
- status.data= &status_field;
- field_list= list_add(NULL, &status);
+
+ state_field.str= (char *) "state";
+ state_field.length= DEFAULT_FIELD_LENGTH;
+ state.data= &state_field;
+
+ field_list= list_add(NULL, &state);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+int Show_instances::write_data(st_net *net)
+{
+ my_bool err_status= FALSE;
+
+ Instance *instance;
+ Instance_map::Iterator iterator(instance_map);
+
+ instance_map->guardian->lock();
+ instance_map->lock();
+
+ while ((instance= iterator.next()))
{
- Instance *instance;
- Instance_map::Iterator iterator(instance_map);
+ Buffer send_buf; /* buffer for packets */
+ uint pos= 0;
+
+ const char *instance_name= instance->options.instance_name.str;
+ const char *state_name= instance_map->get_instance_state_name(instance);
- instance_map->lock();
- while ((instance= iterator.next()))
+ if (store_to_protocol_packet(&send_buf, instance_name, &pos) ||
+ store_to_protocol_packet(&send_buf, state_name, &pos) ||
+ my_net_write(net, send_buf.buffer, pos))
{
- position= 0;
- store_to_protocol_packet(&send_buff, instance->options.instance_name,
- &position);
- if (instance->is_running())
- store_to_protocol_packet(&send_buff, (char*) "online", &position);
- else
- store_to_protocol_packet(&send_buff, (char*) "offline", &position);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ err_status= TRUE;
+ break;
}
- instance_map->unlock();
}
- if (send_eof(net))
- goto err;
- if (net_flush(net))
- goto err;
- return 0;
-err:
- return ER_OUT_OF_RESOURCES;
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+
+ return err_status ? ER_OUT_OF_RESOURCES : 0;
}
-/* implementation for Flush_instances: */
+/**************************************************************************
+ Implementation of Flush_instances.
+**************************************************************************/
-int Flush_instances::execute(struct st_net *net, ulong connection_id)
+/*
+ Implementation of FLUSH INSTANCES statement.
+
+ Possible error codes:
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+ ER_THERE_IS_ACTIVE_INSTACE If there is an active instance
+*/
+
+int Flush_instances::execute(st_net *net, ulong connection_id)
{
- if (instance_map->flush_instances() ||
- net_send_ok(net, connection_id, NULL))
+ instance_map->guardian->lock();
+ instance_map->lock();
+
+ if (instance_map->is_there_active_instance())
+ {
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+ return ER_THERE_IS_ACTIVE_INSTACE;
+ }
+
+ if (instance_map->flush_instances())
+ {
+ instance_map->unlock();
+ instance_map->guardian->unlock();
return ER_OUT_OF_RESOURCES;
+ }
- return 0;
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+
+ return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0;
}
-/* implementation for Show_instance_status: */
+/**************************************************************************
+ Implementation of Abstract_instance_cmd.
+**************************************************************************/
-Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+Abstract_instance_cmd::Abstract_instance_cmd(
+ Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+ :Command(instance_map_arg),
+ instance_name(instance_name_arg)
{
- Instance *instance;
+ /*
+ MT-NOTE: we can not make a search for Instance object here,
+ because it can dissappear after releasing the lock.
+ */
+}
+
+
+int Abstract_instance_cmd::execute(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ instance_map->lock();
+
+ {
+ Instance *instance= instance_map->find(get_instance_name());
+
+ if (!instance)
+ {
+ instance_map->unlock();
+ return ER_BAD_INSTANCE_NAME;
+ }
+
+ err_code= execute_impl(net, instance);
+ }
+
+ instance_map->unlock();
+
+ if (!err_code)
+ err_code= send_ok_response(net, connection_id);
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+ return err_code;
}
-/*
- The method sends a table with a status of requested instance to the client.
+/**************************************************************************
+ Implementation of Show_instance_status.
+**************************************************************************/
- SYNOPSYS
- Show_instance_status::do_command()
- net The network connection to the client.
- instance_name The name of the instance.
+Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
- RETURN
- 0 - ok
- 1 - error occured
+
+/*
+ Implementation of SHOW INSTANCE STATUS statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
+int Show_instance_status::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
-int Show_instance_status::execute(struct st_net *net,
- ulong connection_id)
+ return 0;
+}
+
+
+int Show_instance_status::send_ok_response(st_net *net, ulong connection_id)
{
- enum { MAX_VERSION_LENGTH= 40 };
- Buffer send_buff; /* buffer for packets */
- LIST name, status, version, version_number;
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_status::write_header(st_net *net)
+{
+ LIST name, state, version, version_number, mysqld_compatible;
LIST *field_list;
- NAME_WITH_LENGTH name_field, status_field, version_field,
- version_number_field;
- uint position=0;
+ LEX_STRING name_field, state_field, version_field,
+ version_number_field, mysqld_compatible_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "instance_name";
+ name_field.str= (char *) "instance_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- status_field.name= (char*) "status";
- status_field.length= DEFAULT_FIELD_LENGTH;
- status.data= &status_field;
- version_field.name= (char*) "version";
+
+ state_field.str= (char *) "state";
+ state_field.length= DEFAULT_FIELD_LENGTH;
+ state.data= &state_field;
+
+ version_field.str= (char *) "version";
version_field.length= MAX_VERSION_LENGTH;
version.data= &version_field;
- version_number_field.name= (char*) "version_number";
+
+ version_number_field.str= (char *) "version_number";
version_number_field.length= MAX_VERSION_LENGTH;
version_number.data= &version_number_field;
- field_list= list_add(NULL, &version);
+
+ mysqld_compatible_field.str= (char *) "mysqld_compatible";
+ mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH;
+ mysqld_compatible.data= &mysqld_compatible_field;
+
+ field_list= list_add(NULL, &mysqld_compatible);
+ field_list= list_add(field_list, &version);
field_list= list_add(field_list, &version_number);
- field_list= list_add(field_list, &status);
+ field_list= list_add(field_list, &state);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- {
- Instance *instance;
- store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
- if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
- goto err;
- if (instance->is_running())
- store_to_protocol_packet(&send_buff, (char*) "online", &position);
- else
- store_to_protocol_packet(&send_buff, (char*) "offline", &position);
+int Show_instance_status::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buf; /* buffer for packets */
+ char version_num_buf[MAX_VERSION_LENGTH];
+ uint pos= 0;
- if (instance->options.mysqld_version)
- {
- char parsed_version[MAX_VERSION_LENGTH];
+ const char *state_name;
+ const char *version_tag= "unknown";
+ const char *version_num= "unknown";
+ const char *mysqld_compatible_status;
- parse_version_number(instance->options.mysqld_version, parsed_version,
- sizeof(parsed_version));
- store_to_protocol_packet(&send_buff, parsed_version, &position);
+ instance_map->guardian->lock();
+ state_name= instance_map->get_instance_state_name(instance);
+ mysqld_compatible_status= instance->is_mysqld_compatible() ? "yes" : "no";
+ instance_map->guardian->unlock();
- store_to_protocol_packet(&send_buff, instance->options.mysqld_version,
- &position);
- }
- else
- {
- store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
- store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
- }
+ if (instance->options.mysqld_version)
+ {
+ if (parse_version_number(instance->options.mysqld_version, version_num_buf,
+ sizeof(version_num_buf)))
+ return ER_OUT_OF_RESOURCES;
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ version_num= version_num_buf;
+ version_tag= instance->options.mysqld_version;
}
- if (send_eof(net) || net_flush(net))
- goto err;
+ if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) ||
+ store_to_protocol_packet(&send_buf, state_name, &pos) ||
+ store_to_protocol_packet(&send_buf, version_num, &pos) ||
+ store_to_protocol_packet(&send_buf, version_tag, &pos) ||
+ store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) ||
+ my_net_write(net, send_buf.buffer, (uint) pos))
+ {
+ return ER_OUT_OF_RESOURCES;
+ }
return 0;
+}
-err:
- return ER_OUT_OF_RESOURCES;
+
+/**************************************************************************
+ Implementation of Show_instance_options.
+**************************************************************************/
+
+Show_instance_options::Show_instance_options(
+ Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
}
-/* Implementation for Show_instance_options */
+/*
+ Implementation of SHOW INSTANCE OPTIONS statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
-Show_instance_options::Show_instance_options(Instance_map *instance_map_arg,
- const char *name, uint len):
- Command(instance_map_arg)
+int Show_instance_options::execute_impl(st_net *net, Instance *instance)
{
- Instance *instance;
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+ return 0;
}
-int Show_instance_options::execute(struct st_net *net, ulong connection_id)
+int Show_instance_options::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_options::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name, option;
LIST *field_list;
- NAME_WITH_LENGTH name_field, option_field;
- uint position=0;
+ LEX_STRING name_field, option_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "option_name";
+ name_field.str= (char *) "option_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- option_field.name= (char*) "value";
+
+ option_field.str= (char *) "value";
option_field.length= DEFAULT_FIELD_LENGTH;
option.data= &option_field;
+
field_list= list_add(NULL, &option);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+int Show_instance_options::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ uint pos= 0;
+
+ if (store_to_protocol_packet(&send_buff, "instance_name", &pos) ||
+ store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
{
- Instance *instance;
-
- if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
- goto err;
- store_to_protocol_packet(&send_buff, (char*) "instance_name", &position);
- store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- if ((instance->options.mysqld_path))
- {
- position= 0;
- store_to_protocol_packet(&send_buff, (char*) "mysqld-path", &position);
- store_to_protocol_packet(&send_buff,
- (char*) instance->options.mysqld_path,
- &position);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- }
+ return ER_OUT_OF_RESOURCES;
+ }
- if ((instance->options.nonguarded))
+ /* Loop through the options. */
+
+ for (int i= 0; i < instance->options.get_num_options(); i++)
+ {
+ Named_value option= instance->options.get_option(i);
+ const char *option_value= option.get_value()[0] ? option.get_value() : "";
+
+ pos= 0;
+
+ if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) ||
+ store_to_protocol_packet(&send_buff, option_value, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
{
- position= 0;
- store_to_protocol_packet(&send_buff, (char*) "nonguarded", &position);
- store_to_protocol_packet(&send_buff, "", &position);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ return ER_OUT_OF_RESOURCES;
}
+ }
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Start_instance.
+**************************************************************************/
- /* loop through the options stored in DYNAMIC_ARRAY */
- for (uint i= 0; i < instance->options.options_array.elements; i++)
+Start_instance::Start_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+ Implementation of START INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Start_instance::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= instance->start()))
+ return err_code;
+
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->guard(instance);
+
+ return 0;
+}
+
+
+int Start_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, "Instance started"))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Stop_instance.
+**************************************************************************/
+
+Stop_instance::Stop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+ Implementation of STOP INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Stop_instance::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->stop_guard(instance);
+
+ if ((err_code= instance->stop()))
+ return err_code;
+
+ return 0;
+}
+
+
+int Stop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, NULL))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Create_instance.
+**************************************************************************/
+
+Create_instance::Create_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Command(instance_map_arg),
+ instance_name(instance_name_arg)
+{
+}
+
+
+/*
+ This operation initializes Create_instance object.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing instance options.
+
+ RETURN
+ FALSE On success.
+ TRUE On error.
+*/
+
+bool Create_instance::init(const char **text)
+{
+ return options.init() || parse_args(text);
+}
+
+
+/*
+ This operation parses CREATE INSTANCE options.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing instance options.
+
+ RETURN
+ FALSE On success.
+ TRUE On syntax error.
+*/
+
+bool Create_instance::parse_args(const char **text)
+{
+ uint len;
+
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return FALSE; /* OK: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str= NULL;
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ /* Looking for equal sign. */
+
+ skip_spaces(text);
+
+ if (**text == '=')
{
- char *tmp_option, *option_value;
- get_dynamic(&(instance->options.options_array), (gptr) &tmp_option, i);
- option_value= strchr(tmp_option, '=');
- /* split the option string into two parts if it has a value */
+ ++(*text); /* Skip an equal sign. */
+
+ /* Looking for option value. */
- position= 0;
- if (option_value != NULL)
+ skip_spaces(text);
+
+ if (!**text)
+ return TRUE; /* Syntax error: EOS when option value expected. */
+
+ if (**text != '\'' && **text != '"')
{
- *option_value= 0;
- store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
- store_to_protocol_packet(&send_buff, option_value + 1, &position);
- /* join name and the value into the same option again */
- *option_value= '=';
+ /* Option value is a simple token. */
+
+ LEX_STRING option_value;
+
+ get_word(text, &option_value.length, ALPHANUM);
+
+ if (option_value.length == 0)
+ return TRUE; /* internal parser error. */
+
+ option_value.str= (char *) *text;
+ *text+= option_value.length;
+
+ if (!(option_value_str= Named_value::alloc_str(&option_value)))
+ return TRUE; /* out of memory during parsing. */
}
else
{
- store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
- store_to_protocol_packet(&send_buff, "", &position);
+ /* Option value is a string. */
+
+ if (parse_option_value(*text, &len, &option_value_str))
+ return TRUE; /* Syntax error: invalid string specification. */
+
+ *text+= len;
}
+ }
+
+ if (!option_value_str)
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ {
+ Named_value::free_str(&option_value_str);
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ if (options.add_element(&option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
}
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text);
}
+}
- if (send_eof(net) || net_flush(net))
- goto err;
- return 0;
+/*
+ Implementation of CREATE INSTANCE statement.
+
+ Possible error codes:
+ ER_MALFORMED_INSTANCE_NAME Instance name is malformed
+ ER_CREATE_EXISTING_INSTANCE There is an instance with the given name
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Create_instance::execute(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ /* Check that the name is valid and there is no instance with such name. */
+
+ if (!Instance::is_name_valid(get_instance_name()))
+ return ER_MALFORMED_INSTANCE_NAME;
+
+ /*
+ NOTE: In order to prevent race condition, we should perform all operations
+ on under acquired lock.
+ */
+
+ instance_map->lock();
-err:
- return ER_OUT_OF_RESOURCES;
+ if (instance_map->find(get_instance_name()))
+ {
+ instance_map->unlock();
+ return ER_CREATE_EXISTING_INSTANCE;
+ }
+
+ if ((err_code= instance_map->create_instance(get_instance_name(), &options)))
+ {
+ instance_map->unlock();
+ return err_code;
+ }
+
+ if ((err_code= create_instance_in_file(get_instance_name(), &options)))
+ {
+ Instance *instance= instance_map->find(get_instance_name());
+
+ if (instance)
+ instance_map->remove_instance(instance); /* instance is deleted here. */
+
+ instance_map->unlock();
+ return err_code;
+ }
+
+ /* That's all. */
+
+ instance_map->unlock();
+
+ /* Send the result. */
+
+ if (net_send_ok(net, connection_id, NULL))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
}
-/* Implementation for Start_instance */
+/**************************************************************************
+ Implementation for Drop_instance.
+**************************************************************************/
-Start_instance::Start_instance(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+Drop_instance::Drop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
{
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
}
-int Start_instance::execute(struct st_net *net, ulong connection_id)
+/*
+ Implementation of DROP INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_DROP_ACTIVE_INSTANCE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Drop_instance::execute_impl(st_net *net, Instance *instance)
{
- uint err_code;
- if (instance == 0)
- return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
- else
- {
- if ((err_code= instance->start()))
- return err_code;
+ int err_code;
+
+ /* Check that the instance is offline. */
+
+ if (instance_map->guardian->is_active(instance))
+ return ER_DROP_ACTIVE_INSTANCE;
- if (!(instance->options.nonguarded))
- instance_map->guardian->guard(instance);
+ err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL,
+ get_instance_name()->str, MY_REMOVE_SECTION);
+ DBUG_ASSERT(err_code >= 0 && err_code <= 2);
- net_send_ok(net, connection_id, "Instance started");
- return 0;
+ if (err_code)
+ {
+ log_error("Can not remove instance '%s' from defaults file (%s). "
+ "Original error code: %d.",
+ (const char *) get_instance_name()->str,
+ (const char *) Options::Main::config_file,
+ (int) err_code);
}
+
+ if (err_code)
+ return modify_defaults_to_im_error[err_code];
+
+ /* Remove instance from the instance map hash and Guardian's list. */
+
+ if (!instance->options.nonguarded)
+ instance_map->guardian->stop_guard(instance);
+
+ if ((err_code= instance->stop()))
+ return err_code;
+
+ instance_map->remove_instance(instance);
+
+ return 0;
}
-/* implementation for Show_instance_log: */
+int Drop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, "Instance dropped"))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Show_instance_log.
+**************************************************************************/
Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
- const char *name, uint len,
+ const LEX_STRING *instance_name_arg,
Log_type log_type_arg,
- const char *size_arg,
- const char *offset_arg)
- :Command(instance_map_arg)
+ uint size_arg, uint offset_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg),
+ log_type(log_type_arg),
+ size(size_arg),
+ offset(offset_arg)
{
- Instance *instance;
+}
+
+
+/*
+ Implementation of SHOW INSTANCE LOG statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OFFSET_ERROR We were requested to read negative number of
+ bytes from the log
+ ER_NO_SUCH_LOG The specified type of log is not available for
+ the given instance
+ ER_GUESS_LOGFILE IM wasn't able to figure out the log
+ placement, while it is enabled. Probably user
+ should specify the path to the logfile
+ explicitly.
+ ER_OPEN_LOGFILE Cannot open the logfile
+ ER_READ_FILE Cannot read the logfile
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Show_instance_log::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
- if (offset_arg != NULL)
- offset= atoi(offset_arg);
- else
- offset= 0;
- size= atoi(size_arg);
- log_type= log_type_arg;
+ if ((err_code= check_params(instance)))
+ return err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+ return 0;
}
+int Show_instance_log::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
-/*
- Open the logfile, read requested part of the log and send the info
- to the client.
+ return 0;
+}
- SYNOPSYS
- Show_instance_log::execute()
- net The network connection to the client.
- connection_id Client connection ID
- DESCRIPTION
+int Show_instance_log::check_params(Instance *instance)
+{
+ const char *logpath= instance->options.logs[log_type];
- Send a table with the content of the log requested. The function also
- deals with errro handling, to be verbose.
+ /* Cannot read negative number of bytes. */
- RETURN
- ER_OFFSET_ERROR We were requested to read negative number of bytes
- from the log
- ER_NO_SUCH_LOG The kind log being read is not enabled in the instance
- ER_GUESS_LOGFILE IM wasn't able to figure out the log placement, while
- it is enabled. Probably user should specify the path
- to the logfile explicitly.
- ER_OPEN_LOGFILE Cannot open the logfile
- ER_READ_FILE Cannot read the logfile
- ER_OUT_OF_RESOURCES We weren't able to allocate some resources
-*/
+ if (offset > size)
+ return ER_OFFSET_ERROR;
+
+ /* Instance has no such log. */
+
+ if (logpath == NULL)
+ return ER_NO_SUCH_LOG;
-int Show_instance_log::execute(struct st_net *net, ulong connection_id)
+ if (*logpath == '\0')
+ return ER_GUESS_LOGFILE;
+
+ return 0;
+}
+
+
+int Show_instance_log::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name;
LIST *field_list;
- NAME_WITH_LENGTH name_field;
- uint position= 0;
+ LEX_STRING name_field;
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "Log";
+ /* Create list of the fields to be passed to send_fields(). */
+
+ name_field.str= (char *) "Log";
name_field.length= DEFAULT_FIELD_LENGTH;
- name.data= &name_field;
- field_list= list_add(NULL, &name);
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ name.data= &name_field;
- /* cannot read negative number of bytes */
- if (offset > size)
- return ER_OFFSET_ERROR;
+ field_list= list_add(NULL, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- {
- Instance *instance;
- const char *logpath;
- File fd;
- if ((instance= instance_map->find(instance_name,
- strlen(instance_name))) == NULL)
- goto err;
+int Show_instance_log::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ uint pos= 0;
- logpath= instance->options.logs[log_type];
+ const char *logpath= instance->options.logs[log_type];
+ File fd;
- /* Instance has no such log */
- if (logpath == NULL)
- return ER_NO_SUCH_LOG;
+ size_t buff_size;
+ int read_len;
- if (*logpath == '\0')
- return ER_GUESS_LOGFILE;
+ MY_STAT file_stat;
+ Buffer read_buff;
+ if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0)
+ return ER_OPEN_LOGFILE;
- if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) >= 0)
- {
- size_t buff_size;
- int read_len;
- /* calculate buffer size */
- MY_STAT file_stat;
- Buffer read_buff;
+ /* my_fstat doesn't use the flag parameter */
+ if (my_fstat(fd, &file_stat, MYF(0)))
+ {
+ close(fd);
+ return ER_OUT_OF_RESOURCES;
+ }
- /* my_fstat doesn't use the flag parameter */
- if (my_fstat(fd, &file_stat, MYF(0)))
- goto err;
+ /* calculate buffer size */
+ buff_size= (size - offset);
- buff_size= (size - offset);
+ read_buff.reserve(0, buff_size);
- read_buff.reserve(0, buff_size);
+ /* read in one chunk */
+ read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
- /* read in one chunk */
- read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
+ if ((read_len= my_read(fd, (byte*) read_buff.buffer,
+ buff_size, MYF(0))) < 0)
+ {
+ close(fd);
+ return ER_READ_FILE;
+ }
- if ((read_len= my_read(fd, (byte*) read_buff.buffer,
- buff_size, MYF(0))) < 0)
- return ER_READ_FILE;
- store_to_protocol_packet(&send_buff, read_buff.buffer,
- &position, read_len);
- close(fd);
- }
- else
- return ER_OPEN_LOGFILE;
+ close(fd);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ if (store_to_protocol_packet(&send_buff, read_buff.buffer, &pos, read_len) ||
+ my_net_write(net, send_buff.buffer, pos))
+ {
+ return ER_OUT_OF_RESOURCES;
}
- if (send_eof(net) || net_flush(net))
- goto err;
-
return 0;
-
-err:
- return ER_OUT_OF_RESOURCES;
}
-/* implementation for Show_instance_log_files: */
+/**************************************************************************
+ Implementation of Show_instance_log_files.
+**************************************************************************/
Show_instance_log_files::Show_instance_log_files
- (Instance_map *instance_map_arg, const char *name, uint len)
- :Command(instance_map_arg)
+ (Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
{
- Instance *instance;
-
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
}
/*
- The method sends a table with a list of log files
- used by the instance.
+ Implementation of SHOW INSTANCE LOG FILES statement.
- SYNOPSYS
- Show_instance_log_files::execute()
- net The network connection to the client.
- connection_id The ID of the client connection
-
- RETURN
- ER_BAD_INSTANCE_NAME The instance name specified is not valid
- ER_OUT_OF_RESOURCES some error occured
- 0 - ok
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Show_instance_log_files::execute(struct st_net *net, ulong connection_id)
+int Show_instance_log_files::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
+
+ return 0;
+}
+
+
+int Show_instance_log_files::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_log_files::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name, path, size;
LIST *field_list;
- NAME_WITH_LENGTH name_field, path_field, size_field;
- uint position= 0;
+ LEX_STRING name_field, path_field, size_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "Logfile";
+ name_field.str= (char *) "Logfile";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- path_field.name= (char*) "Path";
+
+ path_field.str= (char *) "Path";
path_field.length= DEFAULT_FIELD_LENGTH;
path.data= &path_field;
- size_field.name= (char*) "File size";
+
+ size_field.str= (char *) "File size";
size_field.length= DEFAULT_FIELD_LENGTH;
size.data= &size_field;
+
field_list= list_add(NULL, &size);
field_list= list_add(field_list, &path);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- Instance *instance;
- if ((instance= instance_map->
- find(instance_name, strlen(instance_name))) == NULL)
- goto err;
+int Show_instance_log_files::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ /*
+ We have alike structure in instance_options.cc. We use such to be able
+ to loop through the options, which we need to handle in some common way.
+ */
+ struct log_files_st
+ {
+ const char *name;
+ const char *value;
+ } logs[]=
+ {
+ {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
+ {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
+ {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
+ {NULL, NULL}
+ };
+ struct log_files_st *log_files;
+
+ for (log_files= logs; log_files->name; log_files++)
{
+ if (!log_files->value)
+ continue;
+
+ struct stat file_stat;
/*
- We have alike structure in instance_options.cc. We use such to be able
- to loop through the options, which we need to handle in some common way.
+ Save some more space for the log file names. In fact all
+ we need is strlen("GENERAL_LOG") + 1
*/
- struct log_files_st
- {
- const char *name;
- const char *value;
- } logs[]=
- {
- {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
- {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
- {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
- {NULL, NULL}
- };
- struct log_files_st *log_files;
-
- for (log_files= logs; log_files->name; log_files++)
+ enum { LOG_NAME_BUFFER_SIZE= 20 };
+ char buff[LOG_NAME_BUFFER_SIZE];
+
+ uint pos= 0;
+
+ const char *log_path= "";
+ const char *log_size= "0";
+
+ if (!stat(log_files->value, &file_stat) &&
+ MY_S_ISREG(file_stat.st_mode))
{
- if (log_files->value != NULL)
- {
- struct stat file_stat;
- /*
- Save some more space for the log file names. In fact all
- we need is srtlen("GENERAL_LOG") + 1
- */
- enum { LOG_NAME_BUFFER_SIZE= 20 };
- char buff[LOG_NAME_BUFFER_SIZE];
-
- position= 0;
- /* store the type of the log in the send buffer */
- store_to_protocol_packet(&send_buff, log_files->name, &position);
- if (stat(log_files->value, &file_stat))
- {
- store_to_protocol_packet(&send_buff, "", &position);
- store_to_protocol_packet(&send_buff, (char*) "0", &position);
- }
- else if (MY_S_ISREG(file_stat.st_mode))
- {
- store_to_protocol_packet(&send_buff,
- (char*) log_files->value,
- &position);
- int10_to_str(file_stat.st_size, buff, 10);
- store_to_protocol_packet(&send_buff, (char*) buff, &position);
- }
-
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- }
+ int10_to_str(file_stat.st_size, buff, 10);
+
+ log_path= log_files->value;
+ log_size= buff;
}
- }
- if (send_eof(net) || net_flush(net))
- goto err;
+ if (store_to_protocol_packet(&send_buff, log_files->name, &pos) ||
+ store_to_protocol_packet(&send_buff, log_path, &pos) ||
+ store_to_protocol_packet(&send_buff, log_size, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
+ return ER_OUT_OF_RESOURCES;
+ }
return 0;
-
-err:
- return ER_OUT_OF_RESOURCES;
}
-/* implementation for SET instance_name.option=option_value: */
+/**************************************************************************
+ Implementation of Abstract_option_cmd.
+**************************************************************************/
+
+/*
+ Instance_options_list -- a data class representing a list of options for
+ some instance.
+*/
-Set_option::Set_option(Instance_map *instance_map_arg,
- const char *name, uint len,
- const char *option_arg, uint option_len_arg,
- const char *option_value_arg, uint option_value_len_arg)
- :Command(instance_map_arg)
+class Instance_options_list
{
- Instance *instance;
+public:
+ Instance_options_list(const LEX_STRING *instance_name_arg);
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- {
- instance_name= instance->options.instance_name;
+public:
+ bool init();
- /* add prefix for add_option */
- if ((option_len_arg < MAX_OPTION_LEN - 1) ||
- (option_value_len_arg < MAX_OPTION_LEN - 1))
- {
- strmake(option, option_arg, option_len_arg);
- strmake(option_value, option_value_arg, option_value_len_arg);
- }
- else
- {
- option[0]= 0;
- option_value[0]= 0;
- }
- instance_name_len= len;
- }
- else
+ const LEX_STRING *get_instance_name() const
{
- instance_name= NULL;
- instance_name_len= 0;
+ return instance_name.get_str();
}
+
+public:
+ /*
+ This member is set and used only in Abstract_option_cmd::execute_impl().
+ Normally it is not used (and should not).
+
+ The problem is that construction and execution of commands are made not
+ in one transaction (not under one lock session). So, we can not initialize
+ instance in constructor and use it in execution.
+ */
+ Instance *instance;
+
+ Named_value_arr options;
+
+private:
+ Instance_name instance_name;
+};
+
+
+/**************************************************************************/
+
+Instance_options_list::Instance_options_list(
+ const LEX_STRING *instance_name_arg)
+ :instance(NULL),
+ instance_name(instance_name_arg)
+{
}
-/*
- The method sends a table with a list of log files
- used by the instance.
+bool Instance_options_list::init()
+{
+ return options.init();
+}
- SYNOPSYS
- Set_option::correct_file()
- skip Skip the option, being searched while writing the result file.
- That is, to delete it.
- DESCRIPTION
+/**************************************************************************/
+
+C_MODE_START
+
+static byte* get_item_key(const byte* item, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ const Instance_options_list *lst= (const Instance_options_list *) item;
+ *len= lst->get_instance_name()->length;
+ return (byte *) lst->get_instance_name()->str;
+}
+
+static void delete_item(void *item)
+{
+ delete (Instance_options_list *) item;
+}
+
+C_MODE_END
+
+
+/**************************************************************************/
+
+Abstract_option_cmd::Abstract_option_cmd(Instance_map *instance_map_arg)
+ :Command(instance_map_arg),
+ initialized(FALSE)
+{
+}
+
+
+Abstract_option_cmd::~Abstract_option_cmd()
+{
+ if (initialized)
+ hash_free(&instance_options_map);
+}
+
+
+bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name,
+ Named_value *option)
+{
+ Instance_options_list *lst= get_instance_options_list(instance_name);
+
+ if (!lst)
+ return TRUE;
+ lst->options.add_element(option);
+
+ return FALSE;
+}
+
+
+bool Abstract_option_cmd::init(const char **text)
+{
+ static const int INITIAL_HASH_SIZE= 16;
+
+ if (hash_init(&instance_options_map, default_charset_info,
+ INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0))
+ return TRUE;
+
+ if (parse_args(text))
+ return TRUE;
+
+ initialized= TRUE;
+
+ return FALSE;
+}
+
+
+/*
Correct the option file. The "skip" option is used to remove the found
option.
+ SYNOPSYS
+ Abstract_option_cmd::correct_file()
+ skip Skip the option, being searched while writing the result file.
+ That is, to delete it.
+
RETURN
- ER_OUT_OF_RESOURCES out of resources
+ 0 Success
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
ER_ACCESS_OPTION_FILE Cannot access the option file
- 0 - ok
*/
-int Set_option::correct_file(int skip)
+int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option,
+ bool skip)
{
- static const int mysys_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
- ER_ACCESS_OPTION_FILE };
- int error;
+ int err_code= modify_defaults_file(Options::Main::config_file,
+ option->get_name(),
+ option->get_value(),
+ instance->get_name()->str,
+ skip);
+
+ DBUG_ASSERT(err_code >= 0 && err_code <= 2);
- error= modify_defaults_file(Options::config_file, option,
- option_value, instance_name, skip);
- DBUG_ASSERT(error >= 0 && error <= 2);
+ if (err_code)
+ {
+ log_error("Can not modify option (%s) in defaults file (%s). "
+ "Original error code: %d.",
+ (const char *) option->get_name(),
+ (const char *) Options::Main::config_file,
+ (int) err_code);
+ }
- return mysys_to_im_error[error];
+ return modify_defaults_to_im_error[err_code];
}
/*
- The method sets an option in the the default config file (/etc/my.cnf).
-
- SYNOPSYS
- Set_option::do_command()
- net The network connection to the client.
-
- RETURN
- 0 - ok
- 1 - error occured
+ Implementation of SET statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_INCOMPATIBLE_OPTION The specified option can not be set for
+ mysqld-compatible instance
+ ER_INSTANCE_IS_ACTIVE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Set_option::do_command(struct st_net *net)
+int Abstract_option_cmd::execute(st_net *net, ulong connection_id)
{
- int error;
+ int err_code;
- /* we must hold the instance_map mutex while changing config file */
instance_map->lock();
- error= correct_file(FALSE);
+
+ err_code= execute_impl(net, connection_id);
+
instance_map->unlock();
- return error;
+ return err_code;
+}
+
+
+Instance_options_list *
+Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name)
+{
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_search(&instance_options_map,
+ (byte *) instance_name->str,
+ instance_name->length);
+
+ if (!lst)
+ {
+ lst= new Instance_options_list(instance_name);
+
+ if (!lst)
+ return NULL;
+
+ if (lst->init() || my_hash_insert(&instance_options_map, (byte *) lst))
+ {
+ delete lst;
+ return NULL;
+ }
+ }
+
+ return lst;
}
-int Set_option::execute(struct st_net *net, ulong connection_id)
+int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id)
{
- if (instance_name != NULL)
+ int err_code;
+
+ /* Check that all the specified instances exist and are offline. */
+
+ for (uint i= 0; i < instance_options_map.records; ++i)
{
- int val;
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_element(&instance_options_map, i);
- val= do_command(net);
+ lst->instance= instance_map->find(lst->get_instance_name());
- if (val == 0)
- net_send_ok(net, connection_id, NULL);
+ if (!lst->instance)
+ return ER_BAD_INSTANCE_NAME;
- return val;
+ if (instance_map->guardian->is_active(lst->instance))
+ return ER_INSTANCE_IS_ACTIVE;
}
- return ER_BAD_INSTANCE_NAME;
+ /* Perform command-specific (SET/UNSET) actions. */
+
+ for (uint i= 0; i < instance_options_map.records; ++i)
+ {
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_element(&instance_options_map, i);
+
+ for (int j= 0; j < lst->options.get_size(); ++j)
+ {
+ Named_value option= lst->options.get_element(j);
+ err_code= process_option(lst->instance, &option);
+
+ if (err_code)
+ break;
+ }
+
+ if (err_code)
+ break;
+ }
+
+ if (err_code == 0)
+ net_send_ok(net, connection_id, NULL);
+
+ return err_code;
}
-/* the only function from Unset_option we need to Implement */
+/**************************************************************************
+ Implementation of Set_option.
+**************************************************************************/
-int Unset_option::do_command(struct st_net *net)
+Set_option::Set_option(Instance_map *instance_map_arg)
+ :Abstract_option_cmd(instance_map_arg)
{
- return correct_file(TRUE);
}
-/* Implementation for Stop_instance: */
+/*
+ This operation parses SET options.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing options.
-Stop_instance::Stop_instance(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+ RETURN
+ FALSE On success.
+ TRUE On syntax error.
+*/
+
+bool Set_option::parse_args(const char **text)
{
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
+ uint len;
+
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return TRUE; /* Syntax error: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING instance_name;
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str= NULL;
+
+ /* Looking for instance name. */
+
+ get_word(text, &instance_name.length, ALPHANUM);
+
+ if (instance_name.length == 0)
+ return TRUE; /* Syntax error: instance name expected. */
+
+ instance_name.str= (char *) *text;
+ *text+= instance_name.length;
+
+ skip_spaces(text);
+
+ /* Check the the delimiter is a dot. */
+
+ if (**text != '.')
+ return TRUE; /* Syntax error: dot expected. */
+
+ ++(*text);
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ /* Looking for equal sign. */
+
+ skip_spaces(text);
+
+ if (**text == '=')
+ {
+ ++(*text); /* Skip an equal sign. */
+
+ /* Looking for option value. */
+
+ skip_spaces(text);
+
+ if (!**text)
+ return TRUE; /* Syntax error: EOS when option value expected. */
+
+ if (**text != '\'' && **text != '"')
+ {
+ /* Option value is a simple token. */
+
+ LEX_STRING option_value;
+
+ get_word(text, &option_value.length, ALPHANUM);
+
+ if (option_value.length == 0)
+ return TRUE; /* internal parser error. */
+
+ option_value.str= (char *) *text;
+ *text+= option_value.length;
+
+ if (!(option_value_str= Named_value::alloc_str(&option_value)))
+ return TRUE; /* out of memory during parsing. */
+ }
+ else
+ {
+ /* Option value is a string. */
+
+ if (parse_option_value(*text, &len, &option_value_str))
+ return TRUE; /* Syntax error: invalid string specification. */
+
+ *text+= len;
+ }
+ }
+
+ if (!option_value_str)
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ {
+ Named_value::free_str(&option_name_str);
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
+
+ if (add_option(&instance_name, &option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
+ }
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text); /* Skip a comma. */
+ }
}
-int Stop_instance::execute(struct st_net *net, ulong connection_id)
+int Set_option::process_option(Instance *instance, Named_value *option)
{
- uint err_code;
+ /* Check that the option is valid. */
+
+ if (instance->is_mysqld_compatible() &&
+ Instance_options::is_option_im_specific(option->get_name()))
+ {
+ log_error("Error: IM-option (%s) can not be used "
+ "in the configuration of mysqld-compatible instance (%s).",
+ (const char *) option->get_name(),
+ (const char *) instance->get_name()->str);
+ return ER_INCOMPATIBLE_OPTION;
+ }
- if (instance == 0)
- return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
+ /* Update the configuration file. */
- if (!(instance->options.nonguarded))
- instance_map->guardian->stop_guard(instance);
+ int err_code= correct_file(instance, option, FALSE);
- if ((err_code= instance->stop()))
+ if (err_code)
+ return err_code;
+
+ /* Update the internal cache. */
+
+ if (instance->options.set_option(option))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Unset_option.
+**************************************************************************/
+
+Unset_option::Unset_option(Instance_map *instance_map_arg)
+ :Abstract_option_cmd(instance_map_arg)
+{
+}
+
+
+/*
+ This operation parses UNSET options.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing options.
+
+ RETURN
+ FALSE On success.
+ TRUE On syntax error.
+*/
+
+bool Unset_option::parse_args(const char **text)
+{
+ uint len;
+
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return TRUE; /* Syntax error: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING instance_name;
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str;
+
+ /* Looking for instance name. */
+
+ get_word(text, &instance_name.length, ALPHANUM);
+
+ if (instance_name.length == 0)
+ return TRUE; /* Syntax error: instance name expected. */
+
+ instance_name.str= (char *) *text;
+ *text+= instance_name.length;
+
+ skip_spaces(text);
+
+ /* Check the the delimiter is a dot. */
+
+ if (**text != '.')
+ return TRUE; /* Syntax error: dot expected. */
+
+ ++(*text); /* Skip a dot. */
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ return TRUE; /* out of memory during parsing. */
+
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ {
+ Named_value::free_str(&option_name_str);
+ return TRUE;
+ }
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
+
+ if (add_option(&instance_name, &option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
+ }
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text); /* Skip a comma. */
+ }
+}
+
+
+/*
+ Implementation of UNSET statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance name specified is not valid
+ ER_INSTANCE_IS_ACTIVE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Unset_option::process_option(Instance *instance, Named_value *option)
+{
+ /* Update the configuration file. */
+
+ int err_code= correct_file(instance, option, TRUE);
+
+ if (err_code)
return err_code;
- net_send_ok(net, connection_id, NULL);
+ /* Update the internal cache. */
+
+ instance->options.unset_option(option->get_name());
+
return 0;
}
-int Syntax_error::execute(struct st_net *net, ulong connection_id)
+/**************************************************************************
+ Implementation of Syntax_error.
+**************************************************************************/
+
+int Syntax_error::execute(st_net *net, ulong connection_id)
{
return ER_SYNTAX_ERROR;
}
diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h
index bfd38d34889..9a9911f2358 100644
--- a/server-tools/instance-manager/commands.h
+++ b/server-tools/instance-manager/commands.h
@@ -16,10 +16,20 @@
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 <hash.h>
+
#include "command.h"
#include "instance.h"
#include "parse.h"
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
+
+
/*
Print all instances of this instance manager.
Grammar: SHOW ISTANCES
@@ -31,12 +41,16 @@ public:
Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
{}
- int execute(struct st_net *net, ulong connection_id);
+ int execute(st_net *net, ulong connection_id);
+
+private:
+ int write_header(st_net *net);
+ int write_data(st_net *net);
};
/*
- Reread configuration file and refresh instance map.
+ Reread configuration file and refresh internal cache.
Grammar: FLUSH INSTANCES
*/
@@ -46,7 +60,43 @@ public:
Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
{}
- int execute(struct st_net *net, ulong connection_id);
+ int execute(st_net *net, ulong connection_id);
+};
+
+
+/*
+ Abstract class for Instance-specific commands.
+*/
+
+class Abstract_instance_cmd : public Command
+{
+public:
+ Abstract_instance_cmd(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg);
+
+public:
+ virtual int execute(st_net *net, ulong connection_id);
+
+protected:
+ /* MT-NOTE: this operation is called under acquired Instance_map's lock. */
+ virtual int execute_impl(st_net *net, Instance *instance) = 0;
+
+ /*
+ This operation is invoked on successful return of execute_impl() and is
+ intended to send closing data.
+
+ MT-NOTE: this operation is called under released Instance_map's lock.
+ */
+ virtual int send_ok_response(st_net *net, ulong connection_id) = 0;
+
+protected:
+ inline const LEX_STRING *get_instance_name() const
+ {
+ return instance_name.get_str();
+ }
+
+private:
+ Instance_name instance_name;
};
@@ -55,31 +105,40 @@ public:
Grammar: SHOW ISTANCE STATUS <instance_name>
*/
-class Show_instance_status : public Command
+class Show_instance_status : public Abstract_instance_cmd
{
public:
-
Show_instance_status(Instance_map *instance_map_arg,
- const char *name, uint len);
- int execute(struct st_net *net, ulong connection_id);
- const char *instance_name;
+ const LEX_STRING *instance_name_arg);
+
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+ int write_header(st_net *net);
+ int write_data(st_net *net, Instance *instance);
};
/*
- Print options if chosen instance.
+ Print options of chosen instance.
Grammar: SHOW INSTANCE OPTIONS <instance_name>
*/
-class Show_instance_options : public Command
+class Show_instance_options : public Abstract_instance_cmd
{
public:
-
Show_instance_options(Instance_map *instance_map_arg,
- const char *name, uint len);
+ const LEX_STRING *instance_name_arg);
- int execute(struct st_net *net, ulong connection_id);
- const char *instance_name;
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+ int write_header(st_net *net);
+ int write_data(st_net *net, Instance *instance);
};
@@ -88,14 +147,15 @@ public:
Grammar: START INSTANCE <instance_name>
*/
-class Start_instance : public Command
+class Start_instance : public Abstract_instance_cmd
{
public:
- Start_instance(Instance_map *instance_map_arg, const char *name, uint len);
+ Start_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg);
- int execute(struct st_net *net, ulong connection_id);
- const char *instance_name;
- Instance *instance;
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
};
@@ -104,33 +164,95 @@ public:
Grammar: STOP INSTANCE <instance_name>
*/
-class Stop_instance : public Command
+class Stop_instance : public Abstract_instance_cmd
{
public:
- Stop_instance(Instance_map *instance_map_arg, const char *name, uint len);
+ Stop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg);
- Instance *instance;
- int execute(struct st_net *net, ulong connection_id);
- const char *instance_name;
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
};
/*
- Print requested part of the log
+ Create an instance.
+ Grammar: CREATE INSTANCE <instance_name> [<options>]
+*/
+
+class Create_instance : public Command
+{
+public:
+ Create_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg);
+
+public:
+ bool init(const char **text);
+
+protected:
+ virtual int execute(st_net *net, ulong connection_id);
+
+ inline const LEX_STRING *get_instance_name() const
+ {
+ return instance_name.get_str();
+ }
+
+private:
+ bool parse_args(const char **text);
+
+private:
+ Instance_name instance_name;
+
+ Named_value_arr options;
+};
+
+
+/*
+ Drop an instance.
+ Grammar: DROP INSTANCE <instance_name>
+
+ Operation is permitted only if the instance is stopped. On successful
+ completion the instance section is removed from config file and the instance
+ is removed from the instance map.
+*/
+
+class Drop_instance : public Abstract_instance_cmd
+{
+public:
+ Drop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg);
+
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
+};
+
+
+/*
+ Print requested part of the log.
Grammar:
- SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end]
+ SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[, offset_from_end]
*/
-class Show_instance_log : public Command
+class Show_instance_log : public Abstract_instance_cmd
{
public:
+ Show_instance_log(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg,
+ Log_type log_type_arg, uint size_arg, uint offset_arg);
+
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+ int check_params(Instance *instance);
+ int write_header(st_net *net);
+ int write_data(st_net *net, Instance *instance);
- Show_instance_log(Instance_map *instance_map_arg, const char *name,
- uint len, Log_type log_type_arg, const char *size_arg,
- const char *offset_arg);
- int execute(struct st_net *net, ulong connection_id);
+private:
Log_type log_type;
- const char *instance_name;
uint size;
uint offset;
};
@@ -141,75 +263,112 @@ public:
Grammar: SHOW <instance_name> LOG FILES
*/
-class Show_instance_log_files : public Command
+class Show_instance_log_files : public Abstract_instance_cmd
{
public:
-
Show_instance_log_files(Instance_map *instance_map_arg,
- const char *name, uint len);
- int execute(struct st_net *net, ulong connection_id);
- const char *instance_name;
- const char *option;
+ const LEX_STRING *instance_name_arg);
+
+protected:
+ virtual int execute_impl(st_net *net, Instance *instance);
+ virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+ int write_header(st_net *net);
+ int write_data(st_net *net, Instance *instance);
};
/*
- Syntax error command. This command is issued if parser reported a syntax
- error. We need it to distinguish the parse error and the situation when
- parser internal error occured. E.g. parsing failed because we hadn't had
- enought memory. In the latter case parse_command() should return an error.
+ Abstract class for option-management commands.
*/
-class Syntax_error : public Command
+class Instance_options_list;
+
+class Abstract_option_cmd : public Command
{
public:
- int execute(struct st_net *net, ulong connection_id);
+ ~Abstract_option_cmd();
+
+public:
+ bool add_option(const LEX_STRING *instance_name, Named_value *option);
+
+public:
+ bool init(const char **text);
+
+ virtual int execute(st_net *net, ulong connection_id);
+
+protected:
+ Abstract_option_cmd(Instance_map *instance_map_arg);
+
+ int correct_file(Instance *instance, Named_value *option, bool skip);
+
+protected:
+ virtual bool parse_args(const char **text) = 0;
+ virtual int process_option(Instance *instance, Named_value *option) = 0;
+
+private:
+ Instance_options_list *
+ get_instance_options_list(const LEX_STRING *instance_name);
+
+ int execute_impl(st_net *net, ulong connection_id);
+
+private:
+ HASH instance_options_map;
+ bool initialized;
};
+
/*
Set an option for the instance.
- Grammar: SET instance_name.option=option_value
+ Grammar: SET instance_name.option[=option_value][, ...]
*/
-class Set_option : public Command
+class Set_option : public Abstract_option_cmd
{
public:
- Set_option(Instance_map *instance_map_arg, const char *name, uint len,
- const char *option_arg, uint option_len,
- const char *option_value_arg, uint option_value_len);
- /*
- the following function is virtual to let Unset_option to use
- */
- virtual int do_command(struct st_net *net);
- int execute(struct st_net *net, ulong connection_id);
+ Set_option(Instance_map *instance_map_arg);
+
protected:
- int correct_file(int skip);
-public:
- const char *instance_name;
- uint instance_name_len;
- /* buffer for the option */
- enum { MAX_OPTION_LEN= 1024 };
- char option[MAX_OPTION_LEN];
- char option_value[MAX_OPTION_LEN];
+ virtual bool parse_args(const char **text);
+ virtual int process_option(Instance *instance, Named_value *option);
};
/*
- Remove option of the instance from config file
- Grammar: UNSET instance_name.option
+ Remove option of the instance.
+ Grammar: UNSET instance_name.option[, ...]
*/
-class Unset_option: public Set_option
+class Unset_option: public Abstract_option_cmd
{
public:
- Unset_option(Instance_map *instance_map_arg, const char *name, uint len,
- const char *option_arg, uint option_len,
- const char *option_value_arg, uint option_value_len):
- Set_option(instance_map_arg, name, len, option_arg, option_len,
- option_value_arg, option_value_len)
- {}
- int do_command(struct st_net *net);
+ Unset_option(Instance_map *instance_map_arg);
+
+protected:
+ virtual bool parse_args(const char **text);
+ virtual int process_option(Instance *instance, Named_value *option);
};
+/*
+ Syntax error command.
+
+ This command is issued if parser reported a syntax error. We need it to
+ distinguish between syntax error and internal parser error. E.g. parsing
+ failed because we hadn't had enought memory. In the latter case the parser
+ just returns NULL.
+*/
+
+class Syntax_error : public Command
+{
+public:
+ /* This is just to avoid compiler warning. */
+ Syntax_error() :Command(NULL)
+ {}
+
+public:
+ int execute(st_net *net, ulong connection_id);
+};
+
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
diff --git a/server-tools/instance-manager/exit_codes.h b/server-tools/instance-manager/exit_codes.h
new file mode 100644
index 00000000000..560ce30b7aa
--- /dev/null
+++ b/server-tools/instance-manager/exit_codes.h
@@ -0,0 +1,41 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
+
+/*
+ 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
+*/
+
+/*
+ This file contains a list of exit codes, which are used when Instance
+ Manager is working in user-management mode.
+*/
+
+const int ERR_OK = 0;
+
+const int ERR_OUT_OF_MEMORY = 1;
+const int ERR_INVALID_USAGE = 2;
+const int ERR_INTERNAL_ERROR = 3;
+const int ERR_IO_ERROR = 4;
+const int ERR_PASSWORD_FILE_CORRUPTED = 5;
+const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6;
+
+const int ERR_CAN_NOT_READ_USER_NAME = 10;
+const int ERR_CAN_NOT_READ_PASSWORD = 11;
+const int ERR_USER_ALREADY_EXISTS = 12;
+const int ERR_USER_NOT_FOUND = 13;
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
index 3be672cd71c..b58241272f9 100644
--- a/server-tools/instance-manager/guardian.cc
+++ b/server-tools/instance-manager/guardian.cc
@@ -21,16 +21,14 @@
#include "guardian.h"
-#include "instance_map.h"
-#include "instance.h"
-#include "mysql_manager_error.h"
-#include "log.h"
-#include "portability.h"
-
#include <string.h>
#include <sys/types.h>
#include <signal.h>
+#include "instance.h"
+#include "instance_map.h"
+#include "log.h"
+#include "mysql_manager_error.h"
pthread_handler_t guardian(void *arg)
@@ -40,6 +38,37 @@ pthread_handler_t guardian(void *arg)
return 0;
}
+
+const char *
+Guardian_thread::get_instance_state_name(enum_instance_state state)
+{
+ switch (state) {
+ case NOT_STARTED:
+ return "offline";
+
+ case STARTING:
+ return "starting";
+
+ case STARTED:
+ return "online";
+
+ case JUST_CRASHED:
+ return "failed";
+
+ case CRASHED:
+ return "crashed";
+
+ case CRASHED_AND_ABANDONED:
+ return "abandoned";
+
+ case STOPPING:
+ return "stopping";
+ }
+
+ return NULL; /* just to ignore compiler warning. */
+}
+
+
Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
uint monitoring_interval_arg) :
@@ -89,10 +118,17 @@ void Guardian_thread::process_instance(Instance *instance,
if (current_node->state == STOPPING)
{
/* this brach is executed during shutdown */
- if (instance->options.shutdown_delay_val)
+ if (instance->options.shutdown_delay)
+ {
+ /*
+ NOTE: it is important to check shutdown_delay here, but use
+ shutdown_delay_val. The idea is that if the option is unset,
+ shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+ */
waitchild= instance->options.shutdown_delay_val;
+ }
- /* this returns true if and only if an instance was stopped for sure */
+ /* this returns TRUE if and only if an instance was stopped for sure */
if (instance->is_crashed())
*guarded_instances= list_delete(*guarded_instances, node);
else if ( (uint) (current_time - current_node->last_checked) > waitchild)
@@ -139,9 +175,12 @@ void Guardian_thread::process_instance(Instance *instance,
case JUST_CRASHED:
if (current_time - current_node->crash_moment <= 2)
{
- instance->start();
- log_info("guardian: starting instance %s",
- instance->options.instance_name);
+ if (instance->is_crashed())
+ {
+ instance->start();
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ }
}
else
current_node->state= CRASHED;
@@ -152,14 +191,21 @@ void Guardian_thread::process_instance(Instance *instance,
{
if ((current_node->restart_counter < restart_retry))
{
- instance->start();
- current_node->last_checked= current_time;
- current_node->restart_counter++;
- log_info("guardian: restarting instance %s",
- instance->options.instance_name);
+ if (instance->is_crashed())
+ {
+ instance->start();
+ current_node->last_checked= current_time;
+ current_node->restart_counter++;
+ log_info("guardian: restarting instance %s",
+ instance->options.instance_name);
+ }
}
else
+ {
+ log_info("guardian: cannot start instance %s. Abandoning attempts "
+ "to (re)start it", instance->options.instance_name);
current_node->state= CRASHED_AND_ABANDONED;
+ }
}
break;
case CRASHED_AND_ABANDONED:
@@ -242,7 +288,9 @@ int Guardian_thread::is_stopped()
SYNOPSYS
Guardian_thread::init()
- NOTE: One should always lock guardian before calling this routine.
+ NOTE: The operation should be invoked with the following locks acquired:
+ - Guardian_thread;
+ - Instance_map;
RETURN
0 - ok
@@ -261,12 +309,11 @@ int Guardian_thread::init()
while ((instance= iterator.next()))
{
- if (!(instance->options.nonguarded))
- if (guard(instance, TRUE)) /* do not lock guardian */
- {
- instance_map->unlock();
- return 1;
- }
+ if (instance->options.nonguarded)
+ continue;
+
+ if (guard(instance, TRUE)) /* do not lock guardian */
+ return 1;
}
return 0;
@@ -334,24 +381,14 @@ int Guardian_thread::stop_guard(Instance *instance)
LIST *node;
pthread_mutex_lock(&LOCK_guardian);
- node= guarded_instances;
- while (node != NULL)
- {
- /*
- We compare only pointers, as we always use pointers from the
- instance_map's MEM_ROOT.
- */
- if (((GUARD_NODE *) node->data)->instance == instance)
- {
- guarded_instances= list_delete(guarded_instances, node);
- pthread_mutex_unlock(&LOCK_guardian);
- return 0;
- }
- else
- node= node->next;
- }
+ node= find_instance_node(instance);
+
+ if (node != NULL)
+ guarded_instances= list_delete(guarded_instances, node);
+
pthread_mutex_unlock(&LOCK_guardian);
+
/* if there is nothing to delete it is also fine */
return 0;
}
@@ -420,7 +457,7 @@ int Guardian_thread::stop_instances(bool stop_instances_arg)
void Guardian_thread::lock()
{
- pthread_mutex_lock(&LOCK_guardian);
+ pthread_mutex_lock(&LOCK_guardian);
}
@@ -428,3 +465,41 @@ void Guardian_thread::unlock()
{
pthread_mutex_unlock(&LOCK_guardian);
}
+
+
+LIST *Guardian_thread::find_instance_node(Instance *instance)
+{
+ LIST *node= guarded_instances;
+
+ while (node != NULL)
+ {
+ /*
+ We compare only pointers, as we always use pointers from the
+ instance_map's MEM_ROOT.
+ */
+ if (((GUARD_NODE *) node->data)->instance == instance)
+ return node;
+
+ node= node->next;
+ }
+
+ return NULL;
+}
+
+
+bool Guardian_thread::is_active(Instance *instance)
+{
+ bool guarded;
+
+ lock();
+
+ guarded= find_instance_node(instance) != NULL;
+
+ /* is_running() can take a long time, so let's unlock mutex first. */
+ unlock();
+
+ if (guarded)
+ return true;
+
+ return instance->is_running();
+}
diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h
index 16b4c373c91..6d3a2b222d7 100644
--- a/server-tools/instance-manager/guardian.h
+++ b/server-tools/instance-manager/guardian.h
@@ -17,11 +17,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
-#include "thread_registry.h"
-
#include <my_sys.h>
#include <my_list.h>
+#include "thread_registry.h"
+
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
@@ -79,6 +79,8 @@ public:
time_t last_checked;
};
+ /* Return client state name. */
+ static const char *get_instance_state_name(enum_instance_state state);
Guardian_thread(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
@@ -94,11 +96,28 @@ public:
int guard(Instance *instance, bool nolock= FALSE);
/* Stop instance protection */
int stop_guard(Instance *instance);
- /* Returns true if guardian thread is stopped */
+ /* Returns TRUE if guardian thread is stopped */
int is_stopped();
void lock();
void unlock();
+ /*
+ Return an internal list node for the given instance if the instance is
+ managed by Guardian. Otherwise, return NULL.
+
+ MT-NOTE: must be called under acquired lock.
+ */
+ LIST *find_instance_node(Instance *instance);
+
+ /* The operation is used to check if the instance is active or not. */
+ bool is_active(Instance *instance);
+
+ /*
+ Return state of the given instance list node. The pointer must specify
+ a valid list node.
+ */
+ inline enum_instance_state get_instance_state(LIST *instance_node);
+
public:
pthread_cond_t COND_guardian;
@@ -108,6 +127,7 @@ private:
/* check instance state and act accordingly */
void process_instance(Instance *instance, GUARD_NODE *current_node,
LIST **guarded_instances, LIST *elem);
+
int stopped;
private:
@@ -115,9 +135,15 @@ private:
Thread_info thread_info;
LIST *guarded_instances;
MEM_ROOT alloc;
- enum { MEM_ROOT_BLOCK_SIZE= 512 };
/* this variable is set to TRUE when we want to stop Guardian thread */
bool shutdown_requested;
};
+
+inline Guardian_thread::enum_instance_state
+Guardian_thread::get_instance_state(LIST *instance_node)
+{
+ return ((GUARD_NODE *) instance_node->data)->state;
+}
+
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 39381b457ab..456052bf7e5 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -20,18 +20,27 @@
#include "instance.h"
-#include "mysql_manager_error.h"
-#include "log.h"
-#include "instance_map.h"
-#include "priv.h"
-#include "portability.h"
+#include <my_global.h>
+#include <mysql.h>
+
+#include <signal.h>
#ifndef __WIN__
#include <sys/wait.h>
#endif
-#include <my_sys.h>
-#include <signal.h>
-#include <m_string.h>
-#include <mysql.h>
+
+#include "guardian.h"
+#include "instance_map.h"
+#include "log.h"
+#include "mysql_manager_error.h"
+#include "portability.h"
+#include "priv.h"
+
+
+const LEX_STRING
+Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_SIZE("mysqld") };
+
+static const char * const INSTANCE_NAME_PREFIX= Instance::DFLT_INSTANCE_NAME.str;
+static const int INSTANCE_NAME_PREFIX_LEN= Instance::DFLT_INSTANCE_NAME.length;
static void start_and_monitor_instance(Instance_options *old_instance_options,
@@ -152,7 +161,7 @@ static int start_process(Instance_options *instance_options,
switch (*pi) {
case 0: /* never happens on QNX */
- execv(instance_options->mysqld_path, instance_options->argv);
+ execv(instance_options->mysqld_path.str, instance_options->argv);
/* exec never returns */
exit(1);
case -1:
@@ -180,7 +189,7 @@ static int start_process(Instance_options *instance_options,
char *cmdline= new char[cmdlen];
if (cmdline == NULL)
return 1;
-
+
cmdline[0]= 0;
for (int i= 0; instance_options->argv[i] != 0; i++)
{
@@ -232,9 +241,7 @@ static int start_process(Instance_options *instance_options,
static void start_and_monitor_instance(Instance_options *old_instance_options,
Instance_map *instance_map)
{
- enum { MAX_INSTANCE_NAME_LEN= 512 };
- char instance_name_buff[MAX_INSTANCE_NAME_LEN];
- uint instance_name_len;
+ Instance_name instance_name(&old_instance_options->instance_name);
Instance *current_instance;
My_process_info process_info;
@@ -248,11 +255,8 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
Save the instance name in the case if Instance object we
are using is destroyed. (E.g. by "FLUSH INSTANCES")
*/
- strmake(instance_name_buff, old_instance_options->instance_name,
- MAX_INSTANCE_NAME_LEN - 1);
- instance_name_len= old_instance_options->instance_name_len;
- log_info("starting instance %s", instance_name_buff);
+ log_info("starting instance %s", (const char *) instance_name.get_c_str());
if (start_process(old_instance_options, &process_info))
{
@@ -266,15 +270,36 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
/* don't check for return value */
wait_process(&process_info);
- current_instance= instance_map->find(instance_name_buff, instance_name_len);
+ instance_map->lock();
+
+ current_instance= instance_map->find(instance_name.get_str());
if (current_instance)
current_instance->set_crash_flag_n_wake_all();
+ instance_map->unlock();
+
return;
}
+bool Instance::is_name_valid(const LEX_STRING *name)
+{
+ const char *name_suffix= name->str + INSTANCE_NAME_PREFIX_LEN;
+
+ if (strncmp(name->str, INSTANCE_NAME_PREFIX, INSTANCE_NAME_PREFIX_LEN) != 0)
+ return FALSE;
+
+ return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
+}
+
+
+bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
+{
+ return strcmp(name->str, INSTANCE_NAME_PREFIX) == 0;
+}
+
+
Instance_map *Instance::get_map()
{
return instance_map;
@@ -309,11 +334,11 @@ int Instance::start()
{
/* clear crash flag */
pthread_mutex_lock(&LOCK_instance);
- crashed= 0;
+ crashed= FALSE;
pthread_mutex_unlock(&LOCK_instance);
- if (!is_running())
+ if (configured && !is_running())
{
remove_pid();
@@ -339,8 +364,8 @@ int Instance::start()
return 0;
}
- /* the instance is started already */
- return ER_INSTANCE_ALREADY_STARTED;
+ /* The instance is started already or misconfigured. */
+ return configured ? ER_INSTANCE_ALREADY_STARTED : ER_INSTANCE_MISCONFIGURED;
}
/*
@@ -363,7 +388,7 @@ void Instance::set_crash_flag_n_wake_all()
{
/* set instance state to crashed */
pthread_mutex_lock(&LOCK_instance);
- crashed= 1;
+ crashed= TRUE;
pthread_mutex_unlock(&LOCK_instance);
/*
@@ -378,7 +403,7 @@ void Instance::set_crash_flag_n_wake_all()
-Instance::Instance(): crashed(0)
+Instance::Instance(): crashed(FALSE), configured(FALSE)
{
pthread_mutex_init(&LOCK_instance, 0);
pthread_cond_init(&COND_instance_stopped, 0);
@@ -392,9 +417,9 @@ Instance::~Instance()
}
-int Instance::is_crashed()
+bool Instance::is_crashed()
{
- int val;
+ bool val;
pthread_mutex_lock(&LOCK_instance);
val= crashed;
pthread_mutex_unlock(&LOCK_instance);
@@ -413,10 +438,17 @@ bool Instance::is_running()
bool return_val;
if (options.mysqld_port)
+ {
+ /*
+ NOTE: it is important to check mysqld_port here, but use
+ mysqld_port_val. The idea is that if the option is unset, mysqld_port
+ will be NULL, but mysqld_port_val will not be reset.
+ */
port= options.mysqld_port_val;
+ }
if (options.mysqld_socket)
- socket= strchr(options.mysqld_socket, '=') + 1;
+ socket= options.mysqld_socket;
/* no port was specified => instance falled back to default value */
if (!options.mysqld_port && !options.mysqld_socket)
@@ -469,8 +501,15 @@ int Instance::stop()
struct timespec timeout;
uint waitchild= (uint) DEFAULT_SHUTDOWN_DELAY;
- if (options.shutdown_delay_val)
+ if (options.shutdown_delay)
+ {
+ /*
+ NOTE: it is important to check shutdown_delay here, but use
+ shutdown_delay_val. The idea is that if the option is unset,
+ shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+ */
waitchild= options.shutdown_delay_val;
+ }
kill_instance(SIGTERM);
/* sleep on condition to wait for SIGCHLD */
@@ -588,20 +627,33 @@ void Instance::kill_instance(int signum)
}
/*
- We execute this function to initialize instance parameters.
- Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
+ Initialize instance parameters.
+
+ SYNOPSYS
+ Instance::init()
+ name_arg name of the instance
+
+ RETURN:
+ 0 ok
+ !0 error
*/
-int Instance::init(const char *name_arg)
+int Instance::init(const LEX_STRING *name_arg)
{
+ mysqld_compatible= is_mysqld_compatible_name(name_arg);
+
return options.init(name_arg);
}
int Instance::complete_initialization(Instance_map *instance_map_arg,
- const char *mysqld_path,
- uint instance_type)
+ const char *mysqld_path)
{
instance_map= instance_map_arg;
- return options.complete_initialization(mysqld_path, instance_type);
+ configured= !options.complete_initialization(mysqld_path);
+ return 0;
+ /*
+ TODO: return actual status (from
+ Instance_options::complete_initialization()) here.
+ */
}
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index adb66991685..1f06cabebf7 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -17,7 +17,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
+#include <m_string.h>
+
#include "instance_options.h"
+#include "priv.h"
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
@@ -25,31 +28,120 @@
class Instance_map;
+
+/*
+ Instance_name -- the class represents instance name -- a string of length
+ less than MAX_INSTANCE_NAME_SIZE.
+
+ Generally, this is just a string with self-memory-management and should be
+ eliminated in the future.
+*/
+
+class Instance_name
+{
+public:
+ Instance_name(const LEX_STRING *name);
+
+public:
+ inline const LEX_STRING *get_str() const
+ {
+ return &str;
+ }
+
+ inline const char *get_c_str() const
+ {
+ return str.str;
+ }
+
+ inline uint get_length() const
+ {
+ return str.length;
+ }
+
+private:
+ LEX_STRING str;
+ char str_buffer[MAX_INSTANCE_NAME_SIZE];
+};
+
+
class Instance
{
public:
+ /*
+ The following two constants defines name of the default mysqld-instance
+ ("mysqld").
+ */
+ static const LEX_STRING DFLT_INSTANCE_NAME;
+
+public:
+ /*
+ The operation is intended to check whether string is a well-formed
+ instance name or not.
+ */
+ static bool is_name_valid(const LEX_STRING *name);
+
+ /*
+ The operation is intended to check if the given instance name is
+ mysqld-compatible or not.
+ */
+ static bool is_mysqld_compatible_name(const LEX_STRING *name);
+
+public:
Instance();
~Instance();
- int init(const char *name);
+ int init(const LEX_STRING *name_arg);
int complete_initialization(Instance_map *instance_map_arg,
- const char *mysqld_path, uint instance_type);
+ const char *mysqld_path);
bool is_running();
int start();
int stop();
/* send a signal to the instance */
void kill_instance(int signo);
- int is_crashed();
+ bool is_crashed();
void set_crash_flag_n_wake_all();
Instance_map *get_map();
+ /*
+ The operation is intended to check if the instance is mysqld-compatible
+ or not.
+ */
+ inline bool is_mysqld_compatible() const;
+
+ /*
+ The operation is intended to check if the instance is configured properly
+ or not. Misconfigured instances are not managed.
+ */
+ inline bool is_configured() const;
+
+ inline const LEX_STRING *get_name() const;
+
public:
enum { DEFAULT_SHUTDOWN_DELAY= 35 };
Instance_options options;
private:
- int crashed;
+ /* This attributes is a flag, specifies if the instance has been crashed. */
+ bool crashed;
+
+ /*
+ This attribute specifies if the instance is configured properly or not.
+ Misconfigured instances are not managed.
+ */
+ bool configured;
+
+ /*
+ This attribute specifies whether the instance is mysqld-compatible or not.
+ Mysqld-compatible instances can contain only mysqld-specific options.
+ At the moment an instance is mysqld-compatible if its name is "mysqld".
+
+ The idea is that [mysqld] section should contain only mysqld-specific
+ options (no Instance Manager-specific options) to be readable by mysqld
+ program.
+ */
+ bool mysqld_compatible;
+
/*
Mutex protecting the instance. Currently we use it to avoid the
double start of the instance. This happens when the instance is starting
@@ -66,4 +158,22 @@ private:
void remove_pid();
};
+
+inline bool Instance::is_mysqld_compatible() const
+{
+ return mysqld_compatible;
+}
+
+
+inline bool Instance::is_configured() const
+{
+ return configured;
+}
+
+
+inline const LEX_STRING *Instance::get_name() const
+{
+ return &options.instance_name;
+}
+
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc
index 543c9c31bfa..c9608fa7c14 100644
--- a/server-tools/instance-manager/instance_map.cc
+++ b/server-tools/instance-manager/instance_map.cc
@@ -20,14 +20,19 @@
#include "instance_map.h"
+#include <my_global.h>
+#include <m_ctype.h>
+#include <mysql_com.h>
+
#include "buffer.h"
+#include "guardian.h"
#include "instance.h"
#include "log.h"
+#include "manager.h"
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
#include "options.h"
-
-#include <m_ctype.h>
-#include <mysql_com.h>
-#include <m_string.h>
+#include "priv.h"
/*
Note: As we are going to suppost different types of connections,
@@ -45,8 +50,8 @@ static byte* get_instance_key(const byte* u, uint* len,
my_bool __attribute__((unused)) t)
{
const Instance *instance= (const Instance *) u;
- *len= instance->options.instance_name_len;
- return (byte *) instance->options.instance_name;
+ *len= instance->options.instance_name.length;
+ return (byte *) instance->options.instance_name.str;
}
static void delete_instance(void *u)
@@ -79,16 +84,60 @@ static void delete_instance(void *u)
static int process_option(void *ctx, const char *group, const char *option)
{
- Instance_map *map= NULL;
+ Instance_map *map= (Instance_map*) ctx;
+ LEX_STRING group_str;
- map = (Instance_map*) ctx;
- return map->process_one_option(group, option);
+ group_str.str= (char *) group;
+ group_str.length= strlen(group);
+
+ return map->process_one_option(&group_str, option);
}
C_MODE_END
/*
+ Parse option string.
+
+ SYNOPSIS
+ parse_option()
+ option_str [IN] option string (e.g. "--name=value")
+ option_name_buf [OUT] parsed name of the option.
+ Must be of (MAX_OPTION_LEN + 1) size.
+ option_value_buf [OUT] parsed value of the option.
+ Must be of (MAX_OPTION_LEN + 1) size.
+
+ DESCRIPTION
+ This is an auxiliary function and should not be used externally. It is
+ intended to parse whole option string into option name and option value.
+*/
+
+static void parse_option(const char *option_str,
+ char *option_name_buf,
+ char *option_value_buf)
+{
+ const char *eq_pos;
+ const char *ptr= option_str;
+
+ while (*ptr == '-')
+ ++ptr;
+
+ strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1);
+
+ eq_pos= strchr(ptr, '=');
+ if (eq_pos)
+ {
+ option_name_buf[eq_pos - ptr]= 0;
+ strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1);
+ }
+ else
+ {
+ option_value_buf[0]= 0;
+ }
+}
+
+
+/*
Process one option from the configuration file.
SYNOPSIS
@@ -103,34 +152,64 @@ C_MODE_END
of the instance map object.
*/
-int Instance_map::process_one_option(const char *group, const char *option)
+int Instance_map::process_one_option(const LEX_STRING *group,
+ const char *option)
{
Instance *instance= NULL;
- static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' };
- if (strncmp(group, prefix, sizeof prefix) == 0 &&
- ((my_isdigit(default_charset_info, group[sizeof prefix]))
- || group[sizeof(prefix)] == '\0'))
+ if (!Instance::is_name_valid(group))
+ {
+ /*
+ Current section name is not a valid instance name.
+ We should skip it w/o error.
+ */
+ return 0;
+ }
+
+ if (!(instance= (Instance *) hash_search(&hash, (byte *) group->str,
+ group->length)))
+ {
+ if (!(instance= new Instance()))
+ return 1;
+
+ if (instance->init(group) || add_instance(instance))
{
- if (!(instance= (Instance *) hash_search(&hash, (byte *) group,
- strlen(group))))
- {
- if (!(instance= new Instance))
- goto err;
- if (instance->init(group) || my_hash_insert(&hash, (byte *) instance))
- goto err_instance;
- }
-
- if (instance->options.add_option(option))
- goto err; /* the instance'll be deleted when we destroy the map */
+ delete instance;
+ return 1;
}
- return 0;
+ if (instance->is_mysqld_compatible())
+ log_info("Warning: instance name '%s' is mysqld-compatible.",
+ (const char *) group->str);
-err_instance:
- delete instance;
-err:
- return 1;
+ log_info("mysqld instance '%s' has been added successfully.",
+ (const char *) group->str);
+ }
+
+ if (option)
+ {
+ char option_name[MAX_OPTION_LEN + 1];
+ char option_value[MAX_OPTION_LEN + 1];
+
+ parse_option(option, option_name, option_value);
+
+ if (instance->is_mysqld_compatible() &&
+ Instance_options::is_option_im_specific(option_name))
+ {
+ log_info("Warning: configuration of mysqld-compatible instance '%s' "
+ "contains IM-specific option '%s'. "
+ "This breaks backward compatibility for the configuration file.",
+ (const char *) group->str,
+ (const char *) option_name);
+ }
+
+ Named_value option(option_name, option_value);
+
+ if (instance->options.set_option(&option))
+ return 1; /* the instance'll be deleted when we destroy the map */
+ }
+
+ return 0;
}
@@ -181,7 +260,7 @@ void Instance_map::unlock()
- pass on the new map to the guardian thread: it will start
all instances that are marked `guarded' and not yet started.
Note, as the check whether an instance is started is currently
- very simple (returns true if there is a MySQL server running
+ very simple (returns TRUE if there is a MySQL server running
at the given port), this function has some peculiar
side-effects:
* if the port number of a running instance was changed, the
@@ -194,9 +273,9 @@ void Instance_map::unlock()
In order to avoid such side effects one should never call
FLUSH INSTANCES without prior stop of all running instances.
- TODO
- FLUSH INSTANCES should return an error if it's called
- while there is a running instance.
+ NOTE: The operation should be invoked with the following locks acquired:
+ - Guardian_thread;
+ - Instance_map;
*/
int Instance_map::flush_instances()
@@ -209,67 +288,169 @@ int Instance_map::flush_instances()
guardian (2) reload the instance map (3) reinitialize the guardian
with new instances.
*/
- guardian->lock();
- pthread_mutex_lock(&LOCK_instance_map);
hash_free(&hash);
hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_instance_key, delete_instance, 0);
+
rc= load();
guardian->init();
- pthread_mutex_unlock(&LOCK_instance_map);
- guardian->unlock();
return rc;
}
-Instance *
-Instance_map::find(const char *name, uint name_len)
+bool Instance_map::is_there_active_instance()
{
Instance *instance;
- pthread_mutex_lock(&LOCK_instance_map);
- instance= (Instance *) hash_search(&hash, (byte *) name, name_len);
- pthread_mutex_unlock(&LOCK_instance_map);
- return instance;
+ Iterator iterator(this);
+
+ while ((instance= iterator.next()))
+ {
+ if (guardian->find_instance_node(instance) != NULL ||
+ instance->is_running())
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
-int Instance_map::complete_initialization()
+int Instance_map::add_instance(Instance *instance)
{
- Instance *instance;
- uint i= 0;
+ return my_hash_insert(&hash, (byte *) instance);
+}
- if (hash.records == 0) /* no instances found */
- {
- if ((instance= new Instance) == 0)
- goto err;
+int Instance_map::remove_instance(Instance *instance)
+{
+ return hash_delete(&hash, (byte *) instance);
+}
- if (instance->init("mysqld") || my_hash_insert(&hash, (byte *) instance))
- goto err_instance;
- /*
- After an instance have been added to the instance_map,
- hash_free should handle it's deletion => goto err, not
- err_instance.
- */
- if (instance->complete_initialization(this, mysqld_path,
- DEFAULT_SINGLE_INSTANCE))
- goto err;
+int Instance_map::create_instance(const LEX_STRING *instance_name,
+ const Named_value_arr *options)
+{
+ Instance *instance= new Instance();
+
+ if (!instance)
+ {
+ log_error("Error: can not initialize (name: '%s').",
+ (const char *) instance_name->str);
+ return ER_OUT_OF_RESOURCES;
}
- else
- while (i < hash.records)
+
+ if (instance->init(instance_name))
+ {
+ log_error("Error: can not initialize (name: '%s').",
+ (const char *) instance_name->str);
+ delete instance;
+ return ER_OUT_OF_RESOURCES;
+ }
+
+ for (int i= 0; options && i < options->get_size(); ++i)
+ {
+ Named_value option= options->get_element(i);
+
+ if (instance->is_mysqld_compatible() &&
+ Instance_options::is_option_im_specific(option.get_name()))
{
- instance= (Instance *) hash_element(&hash, i);
- if (instance->complete_initialization(this, mysqld_path, USUAL_INSTANCE))
- goto err;
- i++;
+ log_error("Error: IM-option (%s) can not be used "
+ "in configuration of mysqld-compatible instance (%s).",
+ (const char *) option.get_name(),
+ (const char *) instance_name->str);
+ delete instance;
+ return ER_INCOMPATIBLE_OPTION;
}
+ instance->options.set_option(&option);
+ }
+
+ if (instance->is_mysqld_compatible())
+ log_info("Warning: instance name '%s' is mysqld-compatible.",
+ (const char *) instance_name->str);
+
+ if (instance->complete_initialization(this, mysqld_path))
+ {
+ log_error("Error: can not complete initialization of instance (name: '%s').",
+ (const char *) instance_name->str);
+ delete instance;
+ return ER_OUT_OF_RESOURCES;
+ /* TODO: return more appropriate error code in this case. */
+ }
+
+ if (add_instance(instance))
+ {
+ log_error("Error: can not register instance (name: '%s').",
+ (const char *) instance_name->str);
+ delete instance;
+ return ER_OUT_OF_RESOURCES;
+ }
+
return 0;
-err_instance:
- delete instance;
-err:
- return 1;
+}
+
+
+Instance * Instance_map::find(const LEX_STRING *name)
+{
+ return (Instance *) hash_search(&hash, (byte *) name->str, name->length);
+}
+
+
+bool Instance_map::complete_initialization()
+{
+ bool mysqld_found;
+
+ /* Complete initialization of all registered instances. */
+
+ for (uint i= 0; i < hash.records; ++i)
+ {
+ Instance *instance= (Instance *) hash_element(&hash, i);
+
+ if (instance->complete_initialization(this, mysqld_path))
+ return TRUE;
+ }
+
+ /* That's all if we are runnning in an ordinary mode. */
+
+ if (!Options::Main::mysqld_safe_compatible)
+ return FALSE;
+
+ /* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */
+
+ mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL;
+
+ if (mysqld_found)
+ return FALSE;
+
+ if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL))
+ {
+ log_error("Error: could not create default instance.");
+ return TRUE;
+ }
+
+ switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL))
+ {
+ case 0:
+ case ER_CONF_FILE_DOES_NOT_EXIST:
+ /*
+ Continue if the instance has been added to the config file
+ successfully, or the config file just does not exist.
+ */
+ break;
+
+ default:
+ log_error("Error: could not add default instance to the config file.");
+
+ Instance *instance= find(&Instance::DFLT_INSTANCE_NAME);
+
+ if (instance)
+ remove_instance(instance); /* instance is deleted here. */
+
+ return TRUE;
+ }
+
+ return FALSE;
}
@@ -297,10 +478,10 @@ int Instance_map::load()
name and start looking for files named "my.cnf.cnf" in all
default dirs. Which is not what we want.
*/
- if (Options::is_forced_default_file)
+ if (Options::Main::is_forced_default_file)
{
snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s",
- Options::config_file);
+ Options::Main::config_file);
argv_options[1]= defaults_file_arg;
argv_options[2]= '\0';
@@ -314,15 +495,12 @@ int Instance_map::load()
If the routine failed, we'll simply fallback to defaults in
complete_initialization().
*/
- if (my_search_option_files(Options::config_file, &argc,
+ if (my_search_option_files(Options::Main::config_file, &argc,
(char ***) &argv, &args_used,
process_option, (void*) this))
log_info("Falling back to compiled-in defaults");
- if (complete_initialization())
- return 1;
-
- return 0;
+ return complete_initialization();
}
@@ -343,3 +521,105 @@ Instance *Instance_map::Iterator::next()
return NULL;
}
+
+const char *Instance_map::get_instance_state_name(Instance *instance)
+{
+ LIST *instance_node;
+
+ if (!instance->is_configured())
+ return "misconfigured";
+
+ if ((instance_node= guardian->find_instance_node(instance)) != NULL)
+ {
+ /* The instance is managed by Guardian: we can report precise state. */
+
+ return Guardian_thread::get_instance_state_name(
+ guardian->get_instance_state(instance_node));
+ }
+
+ /* The instance is not managed by Guardian: we can report status only. */
+
+ return instance->is_running() ? "online" : "offline";
+}
+
+
+/*
+ Create a new configuration section for mysqld-instance in the config file.
+
+ SYNOPSYS
+ create_instance_in_file()
+ instance_name mysqld-instance name
+ options options for the new mysqld-instance
+
+ RETURN
+ 0 On success
+ ER_CONF_FILE_DOES_NOT_EXIST If config file does not exist
+ ER_ACCESS_OPTION_FILE If config file is not writable or some I/O
+ error ocurred during writing configuration
+*/
+
+int create_instance_in_file(const LEX_STRING *instance_name,
+ const Named_value_arr *options)
+{
+ File cnf_file;
+
+ if (my_access(Options::Main::config_file, W_OK))
+ {
+ log_error("Error: configuration file (%s) does not exist.",
+ (const char *) Options::Main::config_file);
+ return ER_CONF_FILE_DOES_NOT_EXIST;
+ }
+
+ cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0));
+
+ if (cnf_file <= 0)
+ {
+ log_error("Error: can not open configuration file (%s): %s.",
+ (const char *) Options::Main::config_file,
+ (const char *) strerror(errno));
+ return ER_ACCESS_OPTION_FILE;
+ }
+
+ if (my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) ||
+ my_write(cnf_file, (byte*)"[", 1, MYF(MY_NABP)) ||
+ my_write(cnf_file, (byte*)instance_name->str, instance_name->length,
+ MYF(MY_NABP)) ||
+ my_write(cnf_file, (byte*)"]", 1, MYF(MY_NABP)) ||
+ my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
+ {
+ log_error("Error: can not write to configuration file (%s): %s.",
+ (const char *) Options::Main::config_file,
+ (const char *) strerror(errno));
+ my_close(cnf_file, MYF(0));
+ return ER_ACCESS_OPTION_FILE;
+ }
+
+ for (int i= 0; options && i < options->get_size(); ++i)
+ {
+ char option_str[MAX_OPTION_STR_LEN];
+ char *ptr;
+ int option_str_len;
+ Named_value option= options->get_element(i);
+
+ ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS);
+
+ if (option.get_value()[0])
+ ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
+
+ option_str_len= ptr - option_str;
+
+ if (my_write(cnf_file, (byte*)option_str, option_str_len, MYF(MY_NABP)) ||
+ my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
+ {
+ log_error("Error: can not write to configuration file (%s): %s.",
+ (const char *) Options::Main::config_file,
+ (const char *) strerror(errno));
+ my_close(cnf_file, MYF(0));
+ return ER_ACCESS_OPTION_FILE;
+ }
+ }
+
+ my_close(cnf_file, MYF(0));
+
+ return 0;
+}
diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h
index d3de42f4d80..8e6d2360652 100644
--- a/server-tools/instance-manager/instance_map.h
+++ b/server-tools/instance-manager/instance_map.h
@@ -17,21 +17,24 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
-
-#include "protocol.h"
-#include "guardian.h"
-
#include <my_sys.h>
+#include <m_string.h>
#include <hash.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
+class Guardian_thread;
class Instance;
+class Named_value_arr;
+
extern int load_all_groups(char ***groups, const char *filename);
extern void free_groups(char **groups);
+extern int create_instance_in_file(const LEX_STRING *instance_name,
+ const Named_value_arr *options);
+
/*
Instance_map - stores all existing instances
@@ -56,22 +59,64 @@ public:
};
friend class Iterator;
public:
- /* returns a pointer to the instance or NULL, if there is no such instance */
- Instance *find(const char *name, uint name_len);
+ /*
+ Return a pointer to the instance or NULL, if there is no such instance.
+ MT-NOTE: must be called under acquired lock.
+ */
+ Instance *find(const LEX_STRING *name);
+ /* Clear the configuration cache and reload the configuration file. */
int flush_instances();
+
+ /* The operation is used to check if there is an active instance or not. */
+ bool is_there_active_instance();
+
void lock();
void unlock();
+
int init();
+
/*
Process a given option and assign it to appropricate instance. This is
required for the option handler, passed to my_search_option_files().
*/
- int process_one_option(const char *group, const char *option);
+ int process_one_option(const LEX_STRING *group, const char *option);
+
+ /*
+ Add an instance into the internal hash.
+
+ MT-NOTE: the operation must be called under acquired lock.
+ */
+ int add_instance(Instance *instance);
+
+ /*
+ Remove instance from the internal hash.
+
+ MT-NOTE: the operation must be called under acquired lock.
+ */
+ int remove_instance(Instance *instance);
+
+ /*
+ Create a new instance and register it in the internal hash.
+
+ MT-NOTE: the operation must be called under acquired lock.
+ */
+ int create_instance(const LEX_STRING *instance_name,
+ const Named_value_arr *options);
Instance_map(const char *default_mysqld_path_arg);
~Instance_map();
+ /*
+ Retrieve client state name of the given instance.
+
+ MT-NOTE: the options must be called under acquired locks of the following
+ objects:
+ - Instance_map;
+ - Guardian_thread;
+ */
+ const char *get_instance_state_name(Instance *instance);
+
public:
const char *mysqld_path;
Guardian_thread *guardian;
@@ -80,7 +125,7 @@ private:
/* loads options from config files */
int load();
/* inits instances argv's after all options have been loaded */
- int complete_initialization();
+ bool complete_initialization();
private:
enum { START_HASH_SIZE = 16 };
pthread_mutex_t LOCK_instance_map;
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
index 8bbd362a15b..b05e40734b7 100644
--- a/server-tools/instance-manager/instance_options.cc
+++ b/server-tools/instance-manager/instance_options.cc
@@ -20,28 +20,24 @@
#include "instance_options.h"
-#include "parse_output.h"
-#include "buffer.h"
-#include "log.h"
-
+#include <my_global.h>
#include <my_sys.h>
-#include <signal.h>
#include <m_string.h>
-#ifdef __WIN__
-#define NEWLINE_LEN 2
-#else
-#define NEWLINE_LEN 1
-#endif
+#include <signal.h>
+
+#include "buffer.h"
+#include "instance.h"
+#include "log.h"
+#include "parse_output.h"
+#include "priv.h"
/* Create "mysqld ..." command in the buffer */
static inline int create_mysqld_command(Buffer *buf,
- const char *mysqld_path_str,
- uint mysqld_path_len,
- const char *option,
- uint option_len)
+ const LEX_STRING *mysqld_path,
+ const LEX_STRING *option)
{
int position= 0;
@@ -50,13 +46,13 @@ static inline int create_mysqld_command(Buffer *buf,
#ifdef __WIN__
buf->append(position++, "\"", 1);
#endif
- buf->append(position, mysqld_path_str, mysqld_path_len);
- position+= mysqld_path_len;
+ buf->append(position, mysqld_path->str, mysqld_path->length);
+ position+= mysqld_path->length;
#ifdef __WIN__
buf->append(position++, "\"", 1);
#endif
/* here the '\0' character is copied from the option string */
- buf->append(position, option, option_len);
+ buf->append(position, option->str, option->length + 1);
return buf->is_error();
}
@@ -64,6 +60,42 @@ static inline int create_mysqld_command(Buffer *buf,
}
+bool Instance_options::is_option_im_specific(const char *option_name)
+{
+ static const char *IM_SPECIFIC_OPTIONS[] =
+ {
+ "nonguarded",
+ "mysqld-path",
+ "shutdown-delay",
+ NULL
+ };
+
+ for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i)
+ {
+ if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+Instance_options::Instance_options()
+ :mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL),
+ mysqld_pid_file(NULL), mysqld_port(NULL), mysqld_port_val(0),
+ nonguarded(NULL), shutdown_delay(NULL), shutdown_delay_val(0),
+ filled_default_options(0)
+{
+ mysqld_path.str= NULL;
+ mysqld_path.length= 0;
+
+ mysqld_real_path.str= NULL;
+ mysqld_real_path.length= 0;
+
+ memset(logs, 0, sizeof(logs));
+}
+
+
/*
Get compiled-in value of default_option
@@ -87,13 +119,13 @@ int Instance_options::get_default_option(char *result, size_t result_len,
const char *option_name)
{
int rc= 1;
- char verbose_option[]= " --no-defaults --verbose --help";
+ LEX_STRING verbose_option=
+ { C_STRING_WITH_SIZE(" --no-defaults --verbose --help") };
- /* reserve space fot the path + option + final '\0' */
- Buffer cmd(mysqld_path_len + sizeof(verbose_option));
+ /* reserve space for the path + option + final '\0' */
+ Buffer cmd(mysqld_path.length + verbose_option.length + 1);
- if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
- verbose_option, sizeof(verbose_option)))
+ if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option))
goto err;
/* +2 eats first "--" from the option string (E.g. "--datadir") */
@@ -121,21 +153,19 @@ err:
int Instance_options::fill_instance_version()
{
- enum { MAX_VERSION_STRING_LENGTH= 160 };
- char result[MAX_VERSION_STRING_LENGTH];
- char version_option[]= " --no-defaults --version";
+ char result[MAX_VERSION_LENGTH];
+ LEX_STRING version_option=
+ { C_STRING_WITH_SIZE(" --no-defaults --version") };
int rc= 1;
- Buffer cmd(mysqld_path_len + sizeof(version_option));
+ Buffer cmd(mysqld_path.length + version_option.length + 1);
- if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
- version_option, sizeof(version_option)))
+ if (create_mysqld_command(&cmd, &mysqld_path, &version_option))
goto err;
- bzero(result, MAX_VERSION_STRING_LENGTH);
+ bzero(result, MAX_VERSION_LENGTH);
- rc= parse_output_and_get_value(cmd.buffer, "Ver",
- result, MAX_VERSION_STRING_LENGTH,
- GET_LINE);
+ rc= parse_output_and_get_value(cmd.buffer, "Ver", result,
+ MAX_VERSION_LENGTH, GET_LINE);
if (*result != '\0')
{
@@ -146,6 +176,7 @@ int Instance_options::fill_instance_version()
start= result;
while (my_isspace(default_charset_info, *start))
++start;
+
mysqld_version= strdup_root(&alloc, start);
}
err:
@@ -178,12 +209,12 @@ err:
int Instance_options::fill_mysqld_real_path()
{
char result[FN_REFLEN];
- char help_option[]= " --no-defaults --help";
+ LEX_STRING help_option=
+ { C_STRING_WITH_SIZE(" --no-defaults --help") };
int rc= 1;
- Buffer cmd(mysqld_path_len + sizeof(help_option));
+ Buffer cmd(mysqld_path.length + help_option.length);
- if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
- help_option, sizeof(help_option)))
+ if (create_mysqld_command(&cmd, &mysqld_path, &help_option))
goto err;
bzero(result, FN_REFLEN);
@@ -198,7 +229,8 @@ int Instance_options::fill_mysqld_real_path()
/* chop the path of at [OPTIONS] */
if ((options_str= strstr(result, "[OPTIONS]")))
*options_str= '\0';
- mysqld_real_path= strdup_root(&alloc, result);
+ mysqld_real_path.str= strdup_root(&alloc, result);
+ mysqld_real_path.length= strlen(mysqld_real_path.str);
}
err:
if (rc)
@@ -255,8 +287,7 @@ int Instance_options::fill_log_options()
else
{
/* below is safe, as --datadir always has a value */
- strmake(datadir,
- strchr(mysqld_datadir, '=') + 1, MAX_LOG_OPTION_LENGTH - 1);
+ strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1);
}
if (gethostname(hostname,sizeof(hostname)-1) < 0)
@@ -342,7 +373,6 @@ err:
int Instance_options::get_pid_filename(char *result)
{
- const char *pid_file= mysqld_pid_file;
char datadir[MAX_PATH_LEN];
if (mysqld_datadir == NULL)
@@ -352,14 +382,10 @@ int Instance_options::get_pid_filename(char *result)
return 1;
}
else
- strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
- "/", NullS);
-
- DBUG_ASSERT(mysqld_pid_file);
- pid_file= strchr(pid_file, '=') + 1;
+ strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS);
/* get the full path to the pidfile */
- my_load_path(result, pid_file, datadir);
+ my_load_path(result, mysqld_pid_file, datadir);
return 0;
}
@@ -388,23 +414,23 @@ pid_t Instance_options::get_pid()
}
-int Instance_options::complete_initialization(const char *default_path,
- uint instance_type)
+int Instance_options::complete_initialization(const char *default_path)
{
+ int arg_idx;
const char *tmp;
char *end;
- if (!mysqld_path && !(mysqld_path= strdup_root(&alloc, default_path)))
+ if (!mysqld_path.str && !(mysqld_path.str= strdup_root(&alloc, default_path)))
goto err;
// it's safe to cast this to char* since this is a buffer we are allocating
- end= convert_dirname((char*)mysqld_path, mysqld_path, NullS);
+ end= convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS);
end[-1]= 0;
- mysqld_path_len= strlen(mysqld_path);
+ mysqld_path.length= strlen(mysqld_path.str);
if (mysqld_port)
- mysqld_port_val= atoi(strchr(mysqld_port, '=') + 1);
+ mysqld_port_val= atoi(mysqld_port);
if (shutdown_delay)
shutdown_delay_val= atoi(shutdown_delay);
@@ -412,7 +438,7 @@ int Instance_options::complete_initialization(const char *default_path,
if (!(tmp= strdup_root(&alloc, "--no-defaults")))
goto err;
- if (!(mysqld_pid_file))
+ if (!mysqld_pid_file)
{
char pidfilename[MAX_PATH_LEN];
char hostname[MAX_PATH_LEN];
@@ -421,26 +447,27 @@ int Instance_options::complete_initialization(const char *default_path,
If we created only one istance [mysqld], because no config. files were
found, we would like to model mysqld pid file values.
*/
+
if (!gethostname(hostname, sizeof(hostname) - 1))
{
- if (instance_type & DEFAULT_SINGLE_INSTANCE)
- strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", hostname,
- ".pid", NullS);
+ if (Instance::is_mysqld_compatible_name(&instance_name))
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS);
else
- strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
- "-", hostname, ".pid", NullS);
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-",
+ hostname, ".pid", NullS);
}
else
{
- if (instance_type & DEFAULT_SINGLE_INSTANCE)
- strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", "mysql",
- ".pid", NullS);
+ if (Instance::is_mysqld_compatible_name(&instance_name))
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS);
else
- strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
- ".pid", NullS);
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid",
+ NullS);
}
- add_option(pidfilename);
+ Named_value option((char *) "pid-file", pidfilename);
+
+ set_option(&option);
}
if (get_pid_filename(pid_file_with_path))
@@ -448,20 +475,37 @@ int Instance_options::complete_initialization(const char *default_path,
/* we need to reserve space for the final zero + possible default options */
if (!(argv= (char**)
- alloc_root(&alloc, (options_array.elements + 1
+ alloc_root(&alloc, (get_num_options() + 1
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
goto err;
+ filled_default_options= 0;
/* the path must be first in the argv */
- if (add_to_argv(mysqld_path))
+ if (add_to_argv(mysqld_path.str))
goto err;
if (add_to_argv(tmp))
goto err;
- memcpy((gptr) (argv + filled_default_options), options_array.buffer,
- options_array.elements*sizeof(char*));
- argv[filled_default_options + options_array.elements]= 0;
+ arg_idx= filled_default_options;
+ for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx)
+ {
+ char option_str[MAX_OPTION_STR_LEN];
+ Named_value option= get_option(opt_idx);
+
+ if (is_option_im_specific(option.get_name()))
+ continue;
+
+ char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(),
+ NullS);
+
+ if (option.get_value()[0])
+ strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
+
+ argv[arg_idx++]= strdup_root(&alloc, option_str);
+ }
+
+ argv[arg_idx]= 0;
if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version())
goto err;
@@ -473,75 +517,91 @@ err:
}
-/*
- Assigns given value to the appropriate option from the class.
+bool Instance_options::set_option(Named_value *option)
+{
+ bool err_status;
+ int idx= find_option(option->get_name());
+ char *option_name_str;
+ char *option_value_str;
- SYNOPSYS
- add_option()
- option string with the option prefixed by --
+ if (!(option_name_str= Named_value::alloc_str(option->get_name())))
+ return TRUE;
- DESCRIPTION
+ if (!(option_value_str= Named_value::alloc_str(option->get_value())))
+ {
+ Named_value::free_str(&option_name_str);
+ return TRUE;
+ }
- The method is called from the option handling routine.
+ Named_value option_copy(option_name_str, option_value_str);
- RETURN
- 0 - ok
- 1 - error occured
-*/
+ if (idx < 0)
+ err_status= options.add_element(&option_copy);
+ else
+ err_status= options.replace_element(idx, &option_copy);
+
+ if (!err_status)
+ update_var(option_copy.get_name(), option_copy.get_value());
+ else
+ option_copy.free();
+
+ return err_status;
+}
-int Instance_options::add_option(const char* option)
+
+void Instance_options::unset_option(const char *option_name)
{
- char *tmp;
- enum { SAVE_VALUE= 1, SAVE_WHOLE, SAVE_WHOLE_AND_ADD };
- struct selected_options_st
+ int idx= find_option(option_name);
+
+ if (idx < 0)
+ return; /* the option has not been set. */
+
+ options.remove_element(idx);
+
+ update_var(option_name, NULL);
+}
+
+
+void Instance_options::update_var(const char *option_name,
+ const char *option_value)
+{
+ struct options_st
{
const char *name;
- uint length;
- const char **value;
- uint type;
- } options[]=
+ uint name_len;
+ const char **var;
+ } options_def[]=
{
- {"--socket=", 9, &mysqld_socket, SAVE_WHOLE_AND_ADD},
- {"--port=", 7, &mysqld_port, SAVE_WHOLE_AND_ADD},
- {"--datadir=", 10, &mysqld_datadir, SAVE_WHOLE_AND_ADD},
- {"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD},
- {"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
- {"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE},
- {"--nonguarded", 9, &nonguarded, SAVE_WHOLE},
- {"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE},
- {NULL, 0, NULL, 0}
+ {"socket", 6, &mysqld_socket},
+ {"port", 4, &mysqld_port},
+ {"datadir", 7, &mysqld_datadir},
+ {"pid-file", 8, &mysqld_pid_file},
+ {"nonguarded", 10, &nonguarded},
+ {"mysqld-path", 11, (const char **) &mysqld_path.str},
+ {"shutdown-delay", 14, &shutdown_delay},
+ {NULL, 0, NULL}
};
- struct selected_options_st *selected_options;
- if (!(tmp= strdup_root(&alloc, option)))
- goto err;
+ for (options_st *opt= options_def; opt->name; ++opt)
+ {
+ if (!strncmp(opt->name, option_name, opt->name_len))
+ {
+ *(opt->var)= option_value;
+ break;
+ }
+ }
+}
- for (selected_options= options; selected_options->name; selected_options++)
- {
- if (strncmp(tmp, selected_options->name, selected_options->length) == 0)
- switch (selected_options->type) {
- case SAVE_WHOLE_AND_ADD:
- *(selected_options->value)= tmp;
- insert_dynamic(&options_array,(gptr) &tmp);
- return 0;
- case SAVE_VALUE:
- *(selected_options->value)= strchr(tmp, '=') + 1;
- return 0;
- case SAVE_WHOLE:
- *(selected_options->value)= tmp;
- return 0;
- default:
- break;
- }
- }
-
- /* if we haven't returned earlier we should just save the option */
- insert_dynamic(&options_array,(gptr) &tmp);
- return 0;
+int Instance_options::find_option(const char *option_name)
+{
+ for (int i= 0; i < get_num_options(); i++)
+ {
+ if (!strcmp(get_option(i).get_name(), option_name))
+ return i;
+ }
-err:
- return 1;
+ return -1;
}
@@ -559,7 +619,10 @@ int Instance_options::add_to_argv(const char* option)
void Instance_options::print_argv()
{
int i;
- printf("printing out an instance %s argv:\n", instance_name);
+
+ printf("printing out an instance %s argv:\n",
+ (const char *) instance_name.str);
+
for (i=0; argv[i] != NULL; i++)
printf("argv: %s\n", argv[i]);
}
@@ -570,17 +633,17 @@ void Instance_options::print_argv()
Return value: 0 - ok. 1 - unable to allocate memory.
*/
-int Instance_options::init(const char *instance_name_arg)
+int Instance_options::init(const LEX_STRING *instance_name_arg)
{
- instance_name_len= strlen(instance_name_arg);
+ instance_name.length= instance_name_arg->length;
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
- if (my_init_dynamic_array(&options_array, sizeof(char*), 0, 32))
+ if (options.init())
goto err;
- if (!(instance_name= strmake_root(&alloc, (char*) instance_name_arg,
- instance_name_len)))
+ if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str,
+ instance_name_arg->length)))
goto err;
return 0;
@@ -593,6 +656,4 @@ err:
Instance_options::~Instance_options()
{
free_root(&alloc, MYF(0));
- delete_dynamic(&options_array);
}
-
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
index b316dbf00fc..c3b0a16a40d 100644
--- a/server-tools/instance-manager/instance_options.h
+++ b/server-tools/instance-manager/instance_options.h
@@ -18,8 +18,9 @@
#include <my_global.h>
#include <my_sys.h>
+
#include "parse.h"
-#include "portability.h"
+#include "portability.h" /* for pid_t on Win32 */
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
@@ -35,25 +36,26 @@
don't have to synchronize between threads.
*/
-#define USUAL_INSTANCE 0
-#define DEFAULT_SINGLE_INSTANCE 1
-
class Instance_options
{
public:
- Instance_options() :
- mysqld_version(0), mysqld_socket(0), mysqld_datadir(0),
- mysqld_bind_address(0), mysqld_pid_file(0), mysqld_port(0),
- mysqld_port_val(0), mysqld_path(0), mysqld_real_path(0),
- nonguarded(0), shutdown_delay(0),
- shutdown_delay_val(0), filled_default_options(0)
- {}
+ /* The operation is used to check if the option is IM-specific or not. */
+ static bool is_option_im_specific(const char *option_name);
+
+public:
+ Instance_options();
~Instance_options();
/* fills in argv */
- int complete_initialization(const char *default_path, uint instance_type);
+ int complete_initialization(const char *default_path);
- int add_option(const char* option);
- int init(const char *instance_name_arg);
+ bool set_option(Named_value *option);
+ void unset_option(const char *option_name);
+
+ inline int get_num_options() const;
+ inline Named_value get_option(int idx) const;
+
+public:
+ int init(const LEX_STRING *instance_name_arg);
pid_t get_pid();
int get_pid_filename(char *result);
int unlink_pidfile();
@@ -66,7 +68,6 @@ public:
*/
enum { MAX_PATH_LEN= 512 };
enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
- enum { MEM_ROOT_BLOCK_SIZE= 512 };
char pid_file_with_path[MAX_PATH_LEN];
char **argv;
/*
@@ -77,23 +78,18 @@ public:
/* We need the some options, so we store them as a separate pointers */
const char *mysqld_socket;
const char *mysqld_datadir;
- const char *mysqld_bind_address;
const char *mysqld_pid_file;
const char *mysqld_port;
uint mysqld_port_val;
- const char *instance_name;
- uint instance_name_len;
- const char *mysqld_path;
- uint mysqld_path_len;
- const char *mysqld_real_path;
+ LEX_STRING instance_name;
+ LEX_STRING mysqld_path;
+ LEX_STRING mysqld_real_path;
const char *nonguarded;
const char *shutdown_delay;
uint shutdown_delay_val;
/* log enums are defined in parse.h */
char *logs[3];
- /* this value is computed and cashed here */
- DYNAMIC_ARRAY options_array;
private:
int fill_log_options();
int fill_instance_version();
@@ -101,9 +97,27 @@ private:
int add_to_argv(const char *option);
int get_default_option(char *result, size_t result_len,
const char *option_name);
+
+ void update_var(const char *option_name, const char *option_value);
+ int find_option(const char *option_name);
+
private:
uint filled_default_options;
MEM_ROOT alloc;
+
+ Named_value_arr options;
};
+
+inline int Instance_options::get_num_options() const
+{
+ return options.get_size();
+}
+
+
+inline Named_value Instance_options::get_option(int idx) const
+{
+ return options.get_element(idx);
+}
+
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 500b25bec03..da9338e28c5 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -19,21 +19,23 @@
#endif
#include "listener.h"
-#include "priv.h"
-#include <m_string.h>
+
+#include <my_global.h>
#include <mysql.h>
#include <violite.h>
+
+#include <sys/stat.h>
#ifndef __WIN__
#include <sys/un.h>
#endif
-#include <sys/stat.h>
-#include "thread_registry.h"
-#include "options.h"
#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
+#include "options.h"
#include "portability.h"
+#include "priv.h"
+#include "thread_registry.h"
/*
@@ -62,8 +64,7 @@ private:
Listener_thread::Listener_thread(const Listener_thread_args &args) :
- Listener_thread_args(args.thread_registry, args.options, args.user_map,
- args.instance_map)
+ Listener_thread_args(args.thread_registry, args.user_map, args.instance_map)
,total_connection_count(0)
,thread_info(pthread_self())
,num_sockets(0)
@@ -234,14 +235,16 @@ int Listener_thread::create_tcp_socket()
bzero(&ip_socket_address, sizeof(ip_socket_address));
ulong im_bind_addr;
- if (options.bind_address != 0)
+ if (Options::Main::bind_address != 0)
{
- if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
+ im_bind_addr= (ulong) inet_addr(Options::Main::bind_address);
+
+ if (im_bind_addr == INADDR_NONE)
im_bind_addr= htonl(INADDR_ANY);
}
else
im_bind_addr= htonl(INADDR_ANY);
- uint im_port= options.port_number;
+ uint im_port= Options::Main::port_number;
ip_socket_address.sin_family= AF_INET;
ip_socket_address.sin_addr.s_addr= im_bind_addr;
@@ -295,7 +298,7 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
bzero(&unix_socket_address, sizeof(unix_socket_address));
unix_socket_address.sun_family= AF_UNIX;
- strmake(unix_socket_address.sun_path, options.socket_file_name,
+ strmake(unix_socket_address.sun_path, Options::Main::socket_file_name,
sizeof(unix_socket_address.sun_path));
unlink(unix_socket_address.sun_path); // in case we have stale socket file
diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h
index 28ccbf91731..c28ab0649d7 100644
--- a/server-tools/instance-manager/listener.h
+++ b/server-tools/instance-manager/listener.h
@@ -27,23 +27,19 @@
pthread_handler_t listener(void *arg);
class Thread_registry;
-struct Options;
class User_map;
class Instance_map;
struct Listener_thread_args
{
Thread_registry &thread_registry;
- const Options &options;
const User_map &user_map;
Instance_map &instance_map;
Listener_thread_args(Thread_registry &thread_registry_arg,
- const Options &options_arg,
const User_map &user_map_arg,
Instance_map &instance_map_arg) :
thread_registry(thread_registry_arg)
- ,options(options_arg)
,user_map(user_map_arg)
,instance_map(instance_map_arg)
{}
diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc
index 3f54bc0649a..a88344f0b91 100644
--- a/server-tools/instance-manager/log.cc
+++ b/server-tools/instance-manager/log.cc
@@ -14,14 +14,16 @@
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 "log.h"
-#include "portability.h"
-#include <stdarg.h>
+
+#include <my_global.h>
#include <m_string.h>
#include <my_sys.h>
+#include <stdarg.h>
+
+#include "portability.h" /* for vsnprintf() on Windows. */
+
/*
TODO:
- add flexible header support
@@ -71,7 +73,7 @@ static inline void log(FILE *file, const char *format, va_list args)
{
int size= sizeof(buff_stack) * 2;
buff_msg= (char*) my_malloc(size, MYF(0));
- while (true)
+ while (TRUE)
{
if (buff_msg == 0)
{
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
index 90d9d04cd36..599131089ed 100644
--- a/server-tools/instance-manager/manager.cc
+++ b/server-tools/instance-manager/manager.cc
@@ -14,39 +14,55 @@
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 "manager.h"
-#include "priv.h"
-#include "thread_registry.h"
-#include "listener.h"
-#include "instance_map.h"
-#include "options.h"
-#include "user_map.h"
-#include "log.h"
-#include "guardian.h"
-
-#include <my_sys.h>
+#include <my_global.h>
#include <m_string.h>
-#include <signal.h>
+#include <my_sys.h>
#include <thr_alarm.h>
+
+#include <signal.h>
#ifndef __WIN__
#include <sys/wait.h>
#endif
+#include "exit_codes.h"
+#include "guardian.h"
+#include "instance_map.h"
+#include "listener.h"
+#include "log.h"
+#include "options.h"
+#include "priv.h"
+#include "thread_registry.h"
+#include "user_map.h"
+
int create_pid_file(const char *pid_file_name, int pid)
{
- if (FILE *pid_file= my_fopen(pid_file_name,
- O_WRONLY | O_CREAT | O_BINARY, MYF(0)))
+ FILE *pid_file;
+
+ if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
+ MYF(0))))
+ {
+ log_error("Error: can not create pid file '%s': %s (errno: %d)",
+ (const char *) pid_file_name,
+ (const char *) strerror(errno),
+ (int) errno);
+ return 1;
+ }
+
+ if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
{
- fprintf(pid_file, "%d\n", (int) pid);
- my_fclose(pid_file, MYF(0));
- return 0;
+ log_error("Error: can not write to pid file '%s': %s (errno: %d)",
+ (const char *) pid_file_name,
+ (const char *) strerror(errno),
+ (int) errno);
+ return 1;
}
- log_error("can't create pid file %s: errno=%d, %s",
- pid_file_name, errno, strerror(errno));
- return 1;
+
+ my_fclose(pid_file, MYF(0));
+
+ return 0;
}
#ifndef __WIN__
@@ -82,14 +98,14 @@ bool have_signal;
void onsignal(int signo)
{
- have_signal= true;
+ have_signal= TRUE;
}
void set_signals(sigset_t *set)
{
signal(SIGINT, onsignal);
signal(SIGTERM, onsignal);
- have_signal= false;
+ have_signal= FALSE;
}
int my_sigwait(const sigset_t *set, int *sig)
@@ -109,10 +125,16 @@ int my_sigwait(const sigset_t *set, int *sig)
listener thread, write pid file and enter into signal handling.
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
+
+ TODO: how about returning error status.
*/
-void manager(const Options &options)
+void manager()
{
+ int err_code;
+ const char *err_msg;
+ bool shutdown_complete= FALSE;
+
Thread_registry thread_registry;
/*
All objects created in the manager() function live as long as
@@ -121,54 +143,61 @@ void manager(const Options &options)
*/
User_map user_map;
- Instance_map instance_map(options.default_mysqld_path);
+ Instance_map instance_map(Options::Main::default_mysqld_path);
Guardian_thread guardian_thread(thread_registry,
&instance_map,
- options.monitoring_interval);
+ Options::Main::monitoring_interval);
- Listener_thread_args listener_args(thread_registry, options, user_map,
- instance_map);
+ Listener_thread_args listener_args(thread_registry, user_map, instance_map);
manager_pid= getpid();
instance_map.guardian= &guardian_thread;
- if (instance_map.init() || user_map.init())
- return;
+ /* Initialize instance map. */
- if (user_map.load(options.password_file_name))
+ if (instance_map.init())
+ {
+ log_error("Error: can not initialize instance list: out of memory.");
return;
+ }
- /* write Instance Manager pid file */
-
- log_info("IM pid file: '%s'; PID: %d.",
- (const char *) options.pid_file_name,
- (int) manager_pid);
+ /* Initialize user map and load password file. */
- if (create_pid_file(options.pid_file_name, manager_pid))
+ if (user_map.init())
+ {
+ log_error("Error: can not initialize user list: out of memory.");
return;
+ }
- sigset_t mask;
- set_signals(&mask);
-
- /* create the listener */
+ if ((err_code= user_map.load(Options::Main::password_file_name, &err_msg)))
{
- pthread_t listener_thd_id;
- pthread_attr_t listener_thd_attr;
- int rc;
+ if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST &&
+ Options::Main::mysqld_safe_compatible)
+ {
+ /*
+ The password file does not exist, but we are running in
+ mysqld_safe-compatible mode. Continue, but complain in log.
+ */
- pthread_attr_init(&listener_thd_attr);
- pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
- rc= set_stacksize_n_create_thread(&listener_thd_id, &listener_thd_attr,
- listener, &listener_args);
- pthread_attr_destroy(&listener_thd_attr);
- if (rc)
+ log_error("Warning: password file does not exist, "
+ "nobody will be able to connect to Instance Manager.");
+ }
+ else
{
- log_error("manager(): set_stacksize_n_create_thread(listener) failed");
- goto err;
+ log_error("Error: %s.", (const char *) err_msg);
+ return;
}
-
}
+ /* write Instance Manager pid file */
+
+ log_info("IM pid file: '%s'; PID: %d.",
+ (const char *) Options::Main::pid_file_name,
+ (int) manager_pid);
+
+ if (create_pid_file(Options::Main::pid_file_name, manager_pid))
+ return; /* necessary logging has been already done. */
+
/* create guardian thread */
{
pthread_t guardian_thd_id;
@@ -198,17 +227,46 @@ void manager(const Options &options)
To work nicely with LinuxThreads, the signal thread is the first thread
in the process.
*/
- int signo;
- bool shutdown_complete;
- shutdown_complete= FALSE;
+ {
+ instance_map.guardian->lock();
+ instance_map.lock();
+
+ int flush_instances_status= instance_map.flush_instances();
+
+ instance_map.unlock();
+ instance_map.guardian->unlock();
+
+ if (flush_instances_status)
+ {
+ log_error("Cannot init instances repository. This might be caused by "
+ "the wrong config file options. For instance, missing mysqld "
+ "binary. Aborting.");
+ return;
+ }
+ }
+
+ /* Initialize signals and alarm-infrastructure. */
+
+ sigset_t mask;
+ set_signals(&mask);
- if (instance_map.flush_instances())
+ /* create the listener */
{
- log_error("Cannot init instances repository. This might be caused by "
- "the wrong config file options. For instance, missing mysqld "
- "binary. Aborting.");
- return;
+ pthread_t listener_thd_id;
+ pthread_attr_t listener_thd_attr;
+ int rc;
+
+ pthread_attr_init(&listener_thd_attr);
+ pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
+ rc= set_stacksize_n_create_thread(&listener_thd_id, &listener_thd_attr,
+ listener, &listener_args);
+ pthread_attr_destroy(&listener_thd_attr);
+ if (rc)
+ {
+ log_error("manager(): set_stacksize_n_create_thread(listener) failed");
+ goto err;
+ }
}
/*
@@ -219,6 +277,7 @@ void manager(const Options &options)
while (!shutdown_complete)
{
+ int signo;
int status= 0;
if ((status= my_sigwait(&mask, &signo)) != 0)
@@ -245,7 +304,7 @@ void manager(const Options &options)
{
if (!guardian_thread.is_stopped())
{
- bool stop_instances= true;
+ bool stop_instances= TRUE;
guardian_thread.request_shutdown(stop_instances);
pthread_cond_signal(&guardian_thread.COND_guardian);
}
@@ -259,7 +318,7 @@ void manager(const Options &options)
err:
/* delete the pid file */
- my_delete(options.pid_file_name, MYF(0));
+ my_delete(Options::Main::pid_file_name, MYF(0));
#ifndef __WIN__
/* free alarm structures */
@@ -267,4 +326,3 @@ err:
/* don't pthread_exit to kill all threads who did not shut down in time */
#endif
}
-
diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h
index 3ddf292132e..7aa4b3e1a96 100644
--- a/server-tools/instance-manager/manager.h
+++ b/server-tools/instance-manager/manager.h
@@ -16,9 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-struct Options;
-
-void manager(const Options &options);
+void manager();
int create_pid_file(const char *pid_file_name, int pid);
diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc
index a9b00b9e01f..af35af1e7b0 100644
--- a/server-tools/instance-manager/messages.cc
+++ b/server-tools/instance-manager/messages.cc
@@ -14,15 +14,14 @@
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 "messages.h"
+#include <my_global.h>
+#include <mysql_com.h>
+
#include "mysqld_error.h"
#include "mysql_manager_error.h"
-#include <mysql_com.h>
-#include <assert.h>
-
static const char *mysqld_error_message(unsigned sql_errno)
{
@@ -70,6 +69,23 @@ static const char *mysqld_error_message(unsigned sql_errno)
"in the instance options";
case ER_ACCESS_OPTION_FILE:
return "Cannot open the option file to edit. Check permissions";
+ case ER_DROP_ACTIVE_INSTANCE:
+ return "Cannot drop an active instance. You should stop it first";
+ case ER_CREATE_EXISTING_INSTANCE:
+ return "Instance already exists";
+ case ER_INSTANCE_MISCONFIGURED:
+ return "Instance is misconfigured. Cannot start it";
+ case ER_MALFORMED_INSTANCE_NAME:
+ return "Malformed instance name.";
+ case ER_INSTANCE_IS_ACTIVE:
+ return "The instance is active. Stop the instance first";
+ case ER_THERE_IS_ACTIVE_INSTACE:
+ return "At least one instance is active. Stop all instances first";
+ case ER_INCOMPATIBLE_OPTION:
+ return "Instance Manager-specific options are prohibited from being used "
+ "in the configuration of mysqld-compatible instances";
+ case ER_CONF_FILE_DOES_NOT_EXIST:
+ return "Configuration file does not exist";
default:
DBUG_ASSERT(0);
return 0;
diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
index dcd1807701f..17cda3af704 100644
--- a/server-tools/instance-manager/mysql_connection.cc
+++ b/server-tools/instance-manager/mysql_connection.cc
@@ -20,22 +20,24 @@
#include "mysql_connection.h"
-#include "priv.h"
-#include "mysql_manager_error.h"
-#include "mysqld_error.h"
-#include "thread_registry.h"
+#include <m_string.h>
+#include <m_string.h>
+#include <my_global.h>
+#include <mysql_com.h>
+#include <mysql.h>
+#include <my_sys.h>
+#include <violite.h>
+
+#include "command.h"
#include "log.h"
-#include "user_map.h"
-#include "protocol.h"
#include "messages.h"
-#include "command.h"
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
#include "parse.h"
-
-#include <mysql.h>
-#include <violite.h>
-#include <mysql_com.h>
-#include <m_string.h>
-#include <my_sys.h>
+#include "priv.h"
+#include "protocol.h"
+#include "thread_registry.h"
+#include "user_map.h"
Mysql_connection_thread_args::Mysql_connection_thread_args(
@@ -56,7 +58,7 @@ Mysql_connection_thread_args::Mysql_connection_thread_args(
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
We use conventional technique to work with classes without exceptions:
- class acquires all vital resource in init(); Thus if init() succeed,
+ class acquires all vital resource in init(); Thus if init() succeed,
a user must call cleanup(). All other methods are valid only between
init() and cleanup().
*/
@@ -190,8 +192,6 @@ void Mysql_connection_thread::run()
int Mysql_connection_thread::check_connection()
{
ulong pkt_len=0; // to hold client reply length
- /* maximum size of the version string */
- enum { MAX_VERSION_LENGTH= 80 };
/* buffer for the first packet */ /* packet contains: */
char buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended
@@ -202,8 +202,8 @@ int Mysql_connection_thread::check_connection()
char *pos= buff;
ulong server_flags;
- memcpy(pos, mysqlmanager_version, mysqlmanager_version_length + 1);
- pos+= mysqlmanager_version_length + 1;
+ memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1);
+ pos+= mysqlmanager_version.length + 1;
int4store((uchar*) pos, connection_id);
pos+= 4;
@@ -271,12 +271,14 @@ int Mysql_connection_thread::check_connection()
const char *user= pos;
const char *password= strend(user)+1;
ulong password_len= *password++;
+ LEX_STRING user_name= { (char *) user, password - user - 2 };
+
if (password_len != SCRAMBLE_LENGTH)
{
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
return 1;
}
- if (user_map.authenticate(user, password-user-2, password, scramble))
+ if (user_map.authenticate(&user_name, password, scramble))
{
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
return 1;
@@ -312,7 +314,7 @@ int Mysql_connection_thread::do_command()
packet= (char*) net.read_pos;
enum enum_server_command command= (enum enum_server_command)
(uchar) *packet;
- log_info("connection %d: packet_length=%d, command=%d",
+ log_info("connection %d: packet_length=%d, command=%d",
connection_id, packet_length, command);
return dispatch_command(command, packet + 1, packet_length - 1);
}
@@ -336,7 +338,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
if (Command *command= parse_command(&instance_map, packet))
{
int res= 0;
- log_info("query for connection %d successefully parsed",connection_id);
+ log_info("query for connection %d successfully parsed",connection_id);
res= command->execute(&net, connection_id);
delete command;
if (!res)
@@ -380,5 +382,5 @@ pthread_handler_t mysql_connection(void *arg)
}
/*
- vim: fdm=marker
+ vim: fdm=marker
*/
diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h
index ff782923a8e..373c7d798a0 100644
--- a/server-tools/instance-manager/mysql_manager_error.h
+++ b/server-tools/instance-manager/mysql_manager_error.h
@@ -29,5 +29,13 @@
#define ER_ACCESS_OPTION_FILE 3008
#define ER_OFFSET_ERROR 3009
#define ER_READ_FILE 3010
+#define ER_DROP_ACTIVE_INSTANCE 3011
+#define ER_CREATE_EXISTING_INSTANCE 3012
+#define ER_INSTANCE_MISCONFIGURED 3013
+#define ER_MALFORMED_INSTANCE_NAME 3014
+#define ER_INSTANCE_IS_ACTIVE 3015
+#define ER_THERE_IS_ACTIVE_INSTACE 3016
+#define ER_INCOMPATIBLE_OPTION 3017
+#define ER_CONF_FILE_DOES_NOT_EXIST 3018
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index ef714099de7..177b761b419 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -15,25 +15,30 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
-#include "manager.h"
-
-#include "options.h"
-#include "log.h"
-
#include <my_sys.h>
+
#include <string.h>
#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
#ifndef __WIN__
#include <pwd.h>
#include <grp.h>
#include <sys/wait.h>
#endif
-#include <sys/types.h>
-#include <sys/stat.h>
+
+#include "log.h"
+#include "manager.h"
+#include "options.h"
+#include "user_management_commands.h"
+
#ifdef __WIN__
-#include "windowsservice.h"
+#include "IMService.h"
+#include "WindowsService.h"
#endif
+
/*
Few notes about Instance Manager architecture:
Instance Manager consisits of two processes: the angel process, and the
@@ -59,13 +64,12 @@
*/
static void init_environment(char *progname);
+
#ifndef __WIN__
static void daemonize(const char *log_file_name);
-static void angel(const Options &options);
+static void angel();
static struct passwd *check_user(const char *user);
static int set_user(const char *user, struct passwd *user_info);
-#else
-int HandleServiceOptions(Options options);
#endif
@@ -81,41 +85,61 @@ int main(int argc, char *argv[])
{
int return_value= 1;
init_environment(argv[0]);
- Options options;
- if (options.load(argc, argv))
- goto err;
+ if ((return_value= Options::load(argc, argv)))
+ goto main_end;
+
+ if (Options::User_management::cmd)
+ {
+ return_value= Options::User_management::cmd->execute();
+
+ goto main_end;
+ }
#ifndef __WIN__
+
struct passwd *user_info;
- if ((user_info= check_user(options.user)))
+ if ((user_info= check_user(Options::Daemon::user)))
{
- if (set_user(options.user, user_info))
- goto err;
+ if (set_user(Options::Daemon::user, user_info))
+ {
+ return_value= 1;
+ goto main_end;
+ }
}
- if (options.run_as_service)
+ if (Options::Daemon::run_as_service)
{
/* forks, and returns only in child */
- daemonize(options.log_file_name);
+ daemonize(Options::Daemon::log_file_name);
/* forks again, and returns only in child: parent becomes angel */
- angel(options);
+ angel();
}
+
+ manager();
+
#else
- if (!options.stand_alone)
+
+ if (!Options::Service::stand_alone)
{
- if (HandleServiceOptions(options))
- goto err;
+ if (HandleServiceOptions())
+ {
+ return_value= 1;
+ goto main_end;
+ }
}
else
+ {
+ manager();
+ }
+
#endif
- manager(options);
return_value= 0;
-err:
- options.cleanup();
+main_end:
+ Options::cleanup();
my_end(0);
return return_value;
}
@@ -200,7 +224,7 @@ static void init_environment(char *progname)
MY_INIT(progname);
log_init();
umask(0117);
- srand(time(0));
+ srand((unsigned int) time(0));
}
@@ -298,7 +322,7 @@ void terminate(int signo)
Angel process will exit silently if mysqlmanager exits normally.
*/
-static void angel(const Options &options)
+static void angel()
{
/* install signal handlers */
sigset_t zeromask; // to sigsuspend in parent
@@ -341,10 +365,10 @@ spawn:
pid= getpid(); /* Get our pid. */
log_info("Angel pid file: '%s'; PID: %d.",
- (const char *) options.angel_pid_file_name,
+ (const char *) Options::Daemon::angel_pid_file_name,
(int) pid);
- create_pid_file(Options::angel_pid_file_name, pid);
+ create_pid_file(Options::Daemon::angel_pid_file_name, pid);
while (child_status == CHILD_OK && is_terminated == 0)
sigsuspend(&zeromask);
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
index 8de592f59b6..31ce5b00190 100644
--- a/server-tools/instance-manager/options.cc
+++ b/server-tools/instance-manager/options.cc
@@ -20,46 +20,89 @@
#include "options.h"
-#include "priv.h"
-#include "portability.h"
+#include <my_global.h>
#include <my_sys.h>
#include <my_getopt.h>
-#include <m_string.h>
#include <mysql_com.h>
+#include "exit_codes.h"
+#include "log.h"
+#include "portability.h"
+#include "priv.h"
+#include "user_management_commands.h"
+
#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
#ifdef __WIN__
-char Options::install_as_service;
-char Options::remove_service;
-char Options::stand_alone;
-char windows_config_file[FN_REFLEN];
-char default_password_file_name[FN_REFLEN];
-char default_log_file_name[FN_REFLEN];
-const char *Options::config_file= windows_config_file;
-#else
-char Options::run_as_service;
-const char *Options::user= 0; /* No default value */
-const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
-const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
-const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE);
-const char *Options::angel_pid_file_name= NULL;
+
+/* Define holders for default values. */
+
+static char win_dflt_config_file_name[FN_REFLEN];
+static char win_dflt_password_file_name[FN_REFLEN];
+static char win_dflt_pid_file_name[FN_REFLEN];
+static char win_dflt_socket_file_name[FN_REFLEN];
+
+static char win_dflt_mysqld_path[FN_REFLEN];
+
+/* Define and initialize Windows-specific options. */
+
+my_bool Options::Service::install_as_service;
+my_bool Options::Service::remove_service;
+my_bool Options::Service::stand_alone;
+
+const char *Options::Main::config_file= win_dflt_config_file_name;
+const char *Options::Main::password_file_name= win_dflt_password_file_name;
+const char *Options::Main::pid_file_name= win_dflt_pid_file_name;
+const char *Options::Main::socket_file_name= win_dflt_socket_file_name;
+
+const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path;
+
+static int setup_windows_defaults();
+
+#else /* UNIX */
+
+/* Define and initialize UNIX-specific options. */
+
+my_bool Options::Daemon::run_as_service= FALSE;
+const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
+const char *Options::Daemon::user= NULL; /* No default value */
+const char *Options::Daemon::angel_pid_file_name= NULL;
+
+const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE);
+const char *
+Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
+const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
+const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
+
+const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
+
#endif
-const char *Options::log_file_name= default_log_file_name;
-const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
-const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
-const char *Options::password_file_name= default_password_file_name;
-const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
-const char *Options::bind_address= 0; /* No default value */
-uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
-uint Options::port_number= DEFAULT_PORT;
-/* just to declare */
+
+/* Remember if the config file was forced. */
+
+bool Options::Main::is_forced_default_file= FALSE;
+
+/* Define and initialize common options. */
+
+const char *Options::Main::bind_address= NULL; /* No default value */
+uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
+uint Options::Main::port_number= DEFAULT_PORT;
+my_bool Options::Main::mysqld_safe_compatible= FALSE;
+
+/* Options::User_management */
+
+char *Options::User_management::user_name= NULL;
+char *Options::User_management::password= NULL;
+
+User_management_cmd *Options::User_management::cmd= NULL;
+
+/* Private members. */
+
char **Options::saved_argv= NULL;
-/* Remember if the config file was forced */
-bool Options::is_forced_default_file= 0;
+
#ifndef DBUG_OFF
-const char *Options::default_dbug_option= "d:t:i:O,im.trace";
+const char *Options::Debug::config_str= "d:t:i:O,im.trace";
#endif
static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid";
@@ -71,24 +114,34 @@ static const int ANGEL_PID_FILE_SUFFIX_LEN= strlen(ANGEL_PID_FILE_SUFFIX);
*/
enum options {
+ OPT_PASSWD= 'P',
+ OPT_USERNAME= 'u',
+ OPT_PASSWORD= 'p',
OPT_LOG= 256,
OPT_PID_FILE,
OPT_SOCKET,
OPT_PASSWORD_FILE,
OPT_MYSQLD_PATH,
-#ifndef __WIN__
- OPT_RUN_AS_SERVICE,
- OPT_USER,
- OPT_ANGEL_PID_FILE,
-#else
+#ifdef __WIN__
OPT_INSTALL_SERVICE,
OPT_REMOVE_SERVICE,
OPT_STAND_ALONE,
+#else
+ OPT_RUN_AS_SERVICE,
+ OPT_USER,
+ OPT_ANGEL_PID_FILE,
#endif
OPT_MONITORING_INTERVAL,
OPT_PORT,
OPT_WAIT_TIMEOUT,
- OPT_BIND_ADDRESS
+ OPT_BIND_ADDRESS,
+ OPT_ADD_USER,
+ OPT_DROP_USER,
+ OPT_EDIT_USER,
+ OPT_CLEAN_PASSWORD_FILE,
+ OPT_CHECK_PASSWORD_FILE,
+ OPT_LIST_USERS,
+ OPT_MYSQLD_SAFE_COMPATIBLE
};
static struct my_option my_long_options[] =
@@ -96,101 +149,158 @@ static struct my_option my_long_options[] =
{ "help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "add-user", OPT_ADD_USER,
+ "Add a user to the password file",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
#ifndef __WIN__
{ "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.",
- (gptr *) &Options::angel_pid_file_name,
- (gptr *) &Options::angel_pid_file_name,
+ (gptr *) &Options::Daemon::angel_pid_file_name,
+ (gptr *) &Options::Daemon::angel_pid_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
#endif
{ "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
- (gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
+ (gptr *) &Options::Main::bind_address,
+ (gptr *) &Options::Main::bind_address,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { "check-password-file", OPT_CHECK_PASSWORD_FILE,
+ "Check the password file for consistency",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "clean-password-file", OPT_CLEAN_PASSWORD_FILE,
+ "Clean the password file",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
#ifndef DBUG_OFF
{"debug", '#', "Debug log.",
- (gptr*) &Options::default_dbug_option, (gptr*) &Options::default_dbug_option,
+ (gptr *) &Options::Debug::config_str,
+ (gptr *) &Options::Debug::config_str,
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{ "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
" Server binary.",
- (gptr *) &Options::default_mysqld_path,
- (gptr *) &Options::default_mysqld_path,
+ (gptr *) &Options::Main::default_mysqld_path,
+ (gptr *) &Options::Main::default_mysqld_path,
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "drop-user", OPT_DROP_USER,
+ "Drop existing user from the password file",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "edit-user", OPT_EDIT_USER,
+ "Edit existing user in the password file",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
#ifdef __WIN__
{ "install", OPT_INSTALL_SERVICE, "Install as system service.",
- (gptr *) &Options::install_as_service, (gptr*) &Options::install_as_service,
+ (gptr *) &Options::Service::install_as_service,
+ (gptr *) &Options::Service::install_as_service,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
#endif
+ { "list-users", OPT_LIST_USERS,
+ "Print out a list of registered users",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+#ifndef __WIN__
{ "log", OPT_LOG, "Path to log file. Used only with --run-as-service.",
- (gptr *) &Options::log_file_name, (gptr *) &Options::log_file_name,
+ (gptr *) &Options::Daemon::log_file_name,
+ (gptr *) &Options::Daemon::log_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+#endif
{ "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor"
" instances in seconds.",
- (gptr *) &Options::monitoring_interval,
- (gptr *) &Options::monitoring_interval,
+ (gptr *) &Options::Main::monitoring_interval,
+ (gptr *) &Options::Main::monitoring_interval,
0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
0, 0, 0, 0, 0 },
- { "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
- GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE,
+ "Start Instance Manager in mysqld_safe compatible manner",
+ (gptr *) &Options::Main::mysqld_safe_compatible,
+ (gptr *) &Options::Main::mysqld_safe_compatible,
+ 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
+
+ { "passwd", OPT_PASSWD,
+ "Prepare an entry for the password file and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "password", OPT_PASSWORD, "Password to update the password file",
+ (gptr *) &Options::User_management::password,
+ (gptr *) &Options::User_management::password,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- { "password-file", OPT_PASSWORD_FILE, "Look for Instance Manager users"
- " and passwords here.",
- (gptr *) &Options::password_file_name,
- (gptr *) &Options::password_file_name,
+ { "password-file", OPT_PASSWORD_FILE,
+ "Look for Instance Manager users and passwords here.",
+ (gptr *) &Options::Main::password_file_name,
+ (gptr *) &Options::Main::password_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "pid-file", OPT_PID_FILE, "Pid file to use.",
- (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name,
+ (gptr *) &Options::Main::pid_file_name,
+ (gptr *) &Options::Main::pid_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "port", OPT_PORT, "Port number to use for connections",
- (gptr *) &Options::port_number, (gptr *) &Options::port_number,
+ (gptr *) &Options::Main::port_number,
+ (gptr *) &Options::Main::port_number,
0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 },
#ifdef __WIN__
{ "remove", OPT_REMOVE_SERVICE, "Remove system service.",
- (gptr *)&Options::remove_service, (gptr*) &Options::remove_service,
+ (gptr *) &Options::Service::remove_service,
+ (gptr *) &Options::Service::remove_service,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
#else
{ "run-as-service", OPT_RUN_AS_SERVICE,
- "Daemonize and start angel process.", (gptr *) &Options::run_as_service,
+ "Daemonize and start angel process.",
+ (gptr *) &Options::Daemon::run_as_service,
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
#endif
{ "socket", OPT_SOCKET, "Socket file to use for connection.",
- (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
+ (gptr *) &Options::Main::socket_file_name,
+ (gptr *) &Options::Main::socket_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
#ifdef __WIN__
{ "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.",
- (gptr *)&Options::stand_alone, (gptr*) &Options::stand_alone,
+ (gptr *) &Options::Service::stand_alone,
+ (gptr *) &Options::Service::stand_alone,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
#else
{ "user", OPT_USER, "Username to start mysqlmanager",
- (gptr *) &Options::user,
- (gptr *) &Options::user,
+ (gptr *) &Options::Daemon::user,
+ (gptr *) &Options::Daemon::user,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
#endif
+ { "username", OPT_USERNAME,
+ "Username to update the password file",
+ (gptr *) &Options::User_management::user_name,
+ (gptr *) &Options::User_management::user_name,
+ 0, GET_STR, REQUIRED_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-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits "
"for activity on a connection before closing it.",
- (gptr *) &net_read_timeout, (gptr *) &net_read_timeout, 0, GET_ULONG,
- REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
+ (gptr *) &net_read_timeout,
+ (gptr *) &net_read_timeout,
+ 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
};
static void version()
{
- printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
+ printf("%s Ver %s for %s on %s\n", my_progname,
+ (const char *) mysqlmanager_version.str,
SYSTEM_TYPE, MACHINE_TYPE);
}
@@ -218,37 +328,6 @@ static void usage()
}
-static void passwd()
-{
- char user[1024], *p;
- const char *pw1, *pw2;
- char pw1msg[]= "Enter password: ";
- char pw2msg[]= "Re-type password: ";
- char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
-
- fprintf(stderr, "Creating record for new user.\n");
- fprintf(stderr, "Enter user name: ");
- if (!fgets(user, sizeof(user), stdin))
- {
- fprintf(stderr, "Unable to read user.\n");
- return;
- }
- if ((p= strchr(user, '\n'))) *p= 0;
-
- pw1= get_tty_password(pw1msg);
- pw2= get_tty_password(pw2msg);
-
- if (strcmp(pw1, pw2))
- {
- fprintf(stderr, "Sorry, passwords do not match.\n");
- return;
- }
-
- make_scrambled_password(crypted_pw, pw1);
- printf("%s:%s\n", user, crypted_pw);
-}
-
-
C_MODE_START
static my_bool
@@ -260,16 +339,52 @@ get_one_option(int optid,
case 'V':
version();
exit(0);
- case 'P':
- passwd();
- exit(0);
+ case OPT_PASSWD:
+ case OPT_ADD_USER:
+ case OPT_DROP_USER:
+ case OPT_EDIT_USER:
+ case OPT_CLEAN_PASSWORD_FILE:
+ case OPT_CHECK_PASSWORD_FILE:
+ case OPT_LIST_USERS:
+ if (Options::User_management::cmd)
+ {
+ fprintf(stderr, "Error: only one password-management command "
+ "can be specified at a time.\n");
+ exit(ERR_INVALID_USAGE);
+ }
+
+ switch (optid) {
+ case OPT_PASSWD:
+ Options::User_management::cmd= new Passwd_cmd();
+ break;
+ case OPT_ADD_USER:
+ Options::User_management::cmd= new Add_user_cmd();
+ break;
+ case OPT_DROP_USER:
+ Options::User_management::cmd= new Drop_user_cmd();
+ break;
+ case OPT_EDIT_USER:
+ Options::User_management::cmd= new Edit_user_cmd();
+ break;
+ case OPT_CLEAN_PASSWORD_FILE:
+ Options::User_management::cmd= new Clean_db_cmd();
+ break;
+ case OPT_CHECK_PASSWORD_FILE:
+ Options::User_management::cmd= new Check_db_cmd();
+ break;
+ case OPT_LIST_USERS:
+ Options::User_management::cmd= new List_users_cmd();
+ break;
+ }
+
+ break;
case '?':
usage();
exit(0);
case '#':
#ifndef DBUG_OFF
- DBUG_SET(argument ? argument : Options::default_dbug_option);
- DBUG_SET_INITIAL(argument ? argument : Options::default_dbug_option);
+ DBUG_SET(argument ? argument : Options::Debug::config_str);
+ DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str);
#endif
break;
}
@@ -295,8 +410,8 @@ int Options::load(int argc, char **argv)
{
if (is_prefix(argv[1], "--defaults-file="))
{
- Options::config_file= strchr(argv[1], '=') + 1;
- Options::is_forced_default_file= 1;
+ Main::config_file= strchr(argv[1], '=') + 1;
+ Main::is_forced_default_file= TRUE;
}
if (is_prefix(argv[1], "--defaults-extra-file=") ||
is_prefix(argv[1], "--no-defaults"))
@@ -305,29 +420,44 @@ int Options::load(int argc, char **argv)
fprintf(stderr, "The --defaults-extra-file and --no-defaults options"
" are not supported by\n"
"Instance Manager. Program aborted.\n");
- goto err;
+ return ERR_INVALID_USAGE;
}
}
#ifdef __WIN__
if (setup_windows_defaults())
- goto err;
+ {
+ fprintf(stderr, "Internal error: could not setup default values.\n");
+ return ERR_OUT_OF_MEMORY;
+ }
#endif
+
/* load_defaults will reset saved_argv with a new allocated list */
saved_argv= argv;
/* config-file options are prepended to command-line ones */
- load_defaults(config_file, default_groups, &argc,
- &saved_argv);
- if ((handle_options(&argc, &saved_argv, my_long_options,
- get_one_option)) != 0)
- goto err;
+ log_info("Loading config file '%s'...",
+ (const char *) Main::config_file);
+
+ load_defaults(Main::config_file, default_groups, &argc, &saved_argv);
+
+ if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option)))
+ return ERR_INVALID_USAGE;
+
+ if (!User_management::cmd &&
+ (User_management::user_name || User_management::password))
+ {
+ fprintf(stderr,
+ "--username and/or --password options have been specified, "
+ "but no password-management command has been given.\n");
+ return ERR_INVALID_USAGE;
+ }
#ifndef __WIN__
- if (Options::run_as_service)
+ if (Options::Daemon::run_as_service)
{
- if (Options::angel_pid_file_name == NULL)
+ if (Options::Daemon::angel_pid_file_name == NULL)
{
/*
Calculate angel pid file on the IM pid file basis: replace the
@@ -339,10 +469,11 @@ int Options::load(int argc, char **argv)
char *base_name_ptr;
char *ext_ptr;
- angel_pid_file_name= (char *) malloc(strlen(Options::pid_file_name) +
- ANGEL_PID_FILE_SUFFIX_LEN);
+ angel_pid_file_name=
+ (char *) malloc(strlen(Options::Main::pid_file_name) +
+ ANGEL_PID_FILE_SUFFIX_LEN);
- strcpy(angel_pid_file_name, Options::pid_file_name);
+ strcpy(angel_pid_file_name, Options::Main::pid_file_name);
base_name_ptr= strrchr(angel_pid_file_name, '/');
@@ -355,54 +486,73 @@ int Options::load(int argc, char **argv)
strcat(angel_pid_file_name, ANGEL_PID_FILE_SUFFIX);
- Options::angel_pid_file_name= angel_pid_file_name;
+ Options::Daemon::angel_pid_file_name= angel_pid_file_name;
}
else
{
- Options::angel_pid_file_name= strdup(Options::angel_pid_file_name);
+ Options::Daemon::angel_pid_file_name=
+ strdup(Options::Daemon::angel_pid_file_name);
}
}
#endif
return 0;
-
-err:
- return 1;
}
void Options::cleanup()
{
- /* free_defaults returns nothing */
- if (Options::saved_argv != NULL)
- free_defaults(Options::saved_argv);
+ if (saved_argv)
+ free_defaults(saved_argv);
+
+ delete User_management::cmd;
#ifndef __WIN__
- if (Options::run_as_service)
- free((void *) Options::angel_pid_file_name);
+ if (Options::Daemon::run_as_service)
+ free((void *) Options::Daemon::angel_pid_file_name);
#endif
}
#ifdef __WIN__
-int Options::setup_windows_defaults()
+static int setup_windows_defaults()
{
- if (!GetModuleFileName(NULL, default_password_file_name,
- sizeof(default_password_file_name)))
- return 1;
- char *filename= strstr(default_password_file_name, ".exe");
- strcpy(filename, ".passwd");
-
- if (!GetModuleFileName(NULL, default_log_file_name,
- sizeof(default_log_file_name)))
+ char module_full_name[FN_REFLEN];
+ char dir_name[FN_REFLEN];
+ char base_name[FN_REFLEN];
+ char im_name[FN_REFLEN];
+ char *base_name_ptr;
+ char *ptr;
+
+ /* Determine dirname and basename. */
+
+ if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) ||
+ !GetFullPathName(module_full_name, sizeof (dir_name), dir_name,
+ &base_name_ptr))
+ {
return 1;
- filename= strstr(default_log_file_name, ".exe");
- strcpy(filename, ".log");
+ }
+
+ strmake(base_name, base_name_ptr, FN_REFLEN);
+ *base_name_ptr= 0;
+
+ strmake(im_name, base_name, FN_REFLEN);
+ ptr= strrchr(im_name, '.');
+
+ if (!ptr)
+ return 1;
+
+ *ptr= 0;
+
+ /* Initialize the defaults. */
+
+ strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS);
+ strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS);
+ strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT,
+ NullS);
+ strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS);
+ strxmov(win_dflt_socket_file_name, dir_name, im_name, DFLT_SOCKET_FILE_EXT,
+ NullS);
- if (!GetModuleFileName(NULL, windows_config_file,
- sizeof(windows_config_file)))
- return 1;
- char *slash= strrchr(windows_config_file, '\\');
- strcpy(slash, "\\my.ini");
return 0;
}
diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h
index 00a50a2acdb..5c54ff201b2 100644
--- a/server-tools/instance-manager/options.h
+++ b/server-tools/instance-manager/options.h
@@ -17,50 +17,87 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
- Options - all possible options for the instance manager grouped in one
- struct.
+ Options - all possible command-line options for the Instance Manager grouped
+ in one struct.
*/
+
#include <my_global.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
+class User_management_cmd;
+
struct Options
{
-#ifdef __WIN__
- static char install_as_service;
- static char remove_service;
- static char stand_alone;
-#else
- static char run_as_service; /* handle_options doesn't support bool */
- static const char *user;
- static const char *angel_pid_file_name;
-#endif
- static bool is_forced_default_file;
- static const char *log_file_name;
- static const char *pid_file_name;
- static const char *socket_file_name;
- static const char *password_file_name;
- static const char *default_mysqld_path;
- /* the option which should be passed to process_default_option_files */
- static uint monitoring_interval;
- static uint port_number;
- static const char *bind_address;
- static const char *config_file;
+ /*
+ NOTE: handle_options() expects value of my_bool type for GET_BOOL
+ accessor (i.e. bool must not be used).
+ */
- /* argv pointer returned by load_defaults() to be used by free_defaults() */
- static char **saved_argv;
+ struct User_management
+ {
+ static User_management_cmd *cmd;
+
+ static char *user_name;
+ static char *password;
+ };
+
+ struct Main
+ {
+ /* this is not an option parsed by handle_options(). */
+ static bool is_forced_default_file;
+
+ static const char *pid_file_name;
+ static const char *socket_file_name;
+ static const char *password_file_name;
+ static const char *default_mysqld_path;
+ static uint monitoring_interval;
+ static uint port_number;
+ static const char *bind_address;
+ static const char *config_file;
+ static my_bool mysqld_safe_compatible;
+ };
#ifndef DBUG_OFF
- static const char *default_dbug_option;
+ struct Debug
+ {
+ static const char *config_str;
+ };
#endif
- int load(int argc, char **argv);
- void cleanup();
-#ifdef __WIN__
- int setup_windows_defaults();
+#ifndef __WIN__
+
+ struct Daemon
+ {
+ static my_bool run_as_service;
+ static const char *log_file_name;
+ static const char *user;
+ static const char *angel_pid_file_name;
+ };
+
+#else
+
+ struct Service
+ {
+ static my_bool install_as_service;
+ static my_bool remove_service;
+ static my_bool stand_alone;
+ };
+
#endif
+
+public:
+ static int load(int argc, char **argv);
+ static void cleanup();
+
+private:
+ Options(); /* Deny instantiation of this class. */
+
+private:
+ /* argv pointer returned by load_defaults() to be used by free_defaults() */
+ static char **saved_argv;
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index 14b3db16b45..4e931488fce 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -17,12 +17,12 @@
#include "parse.h"
#include "commands.h"
-#include <string.h>
-
enum Token
{
- TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */
+ TOK_CREATE= 0,
+ TOK_DROP,
+ TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */
TOK_FILES,
TOK_FLUSH,
TOK_GENERAL,
@@ -50,6 +50,8 @@ struct tokens_st
static struct tokens_st tokens[]= {
+ {6, "CREATE"},
+ {4, "DROP"},
{5, "ERROR"},
{5, "FILES"},
{5, "FLUSH"},
@@ -67,6 +69,37 @@ static struct tokens_st tokens[]= {
{5, "UNSET"}
};
+/************************************************************************/
+
+Named_value_arr::Named_value_arr() :
+ initialized(FALSE)
+{
+}
+
+
+bool Named_value_arr::init()
+{
+ if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
+ return TRUE;
+
+ initialized= TRUE;
+
+ return FALSE;
+}
+
+
+Named_value_arr::~Named_value_arr()
+{
+ if (!initialized)
+ return;
+
+ for (int i= 0; i < get_size(); ++i)
+ get_element(i).free();
+
+ delete_dynamic(&arr);
+}
+
+/************************************************************************/
/*
Returns token no if word corresponds to some token, otherwise returns
@@ -104,53 +137,200 @@ Token shift_token(const char **text, uint *word_len)
}
-int get_text_id(const char **text, uint *word_len, const char **id)
+int get_text_id(const char **text, LEX_STRING *token)
{
- get_word(text, word_len);
- if (*word_len == 0)
+ get_word(text, &token->length);
+ if (token->length == 0)
return 1;
- *id= *text;
+ token->str= (char *) *text;
return 0;
}
+static bool parse_long(const LEX_STRING *token, long *value)
+{
+ int err_code;
+ char *end_ptr= token->str + token->length;
+
+ *value= my_strtoll10(token->str, &end_ptr, &err_code);
+
+ return err_code != 0;
+}
+
+
+bool parse_option_value(const char *text, uint *text_len, char **value)
+{
+ char beginning_quote;
+ const char *text_start_ptr;
+ char *v;
+ bool escape_mode= FALSE;
+
+ if (!*text || (*text != '\'' && *text != '"'))
+ return TRUE; /* syntax error: string expected. */
+
+ beginning_quote= *text;
+
+ ++text; /* skip the beginning quote. */
+
+ text_start_ptr= text;
+
+ if (!(v= Named_value::alloc_str(text)))
+ return TRUE;
+
+ *value= v;
+
+ while (TRUE)
+ {
+ if (!*text)
+ {
+ Named_value::free_str(value);
+ return TRUE; /* syntax error: missing terminating ' character. */
+ }
+
+ if (*text == '\n' || *text == '\r')
+ {
+ Named_value::free_str(value);
+ return TRUE; /* syntax error: option value should be a single line. */
+ }
+
+ if (!escape_mode && *text == beginning_quote)
+ break;
+
+ if (escape_mode)
+ {
+ switch (*text)
+ {
+ case 'b': /* \b -- backspace */
+ if (v > *value)
+ --v;
+ break;
+
+ case 't': /* \t -- tab */
+ *v= '\t';
+ ++v;
+ break;
+
+ case 'n': /* \n -- newline */
+ *v= '\n';
+ ++v;
+ break;
+
+ case 'r': /* \r -- carriage return */
+ *v= '\r';
+ ++v;
+ break;
+
+ case '\\': /* \\ -- back slash */
+ *v= '\\';
+ ++v;
+ break;
+
+ case 's': /* \s -- space */
+ *v= ' ';
+ ++v;
+ break;
+
+ default: /* Unknown escape sequence. Treat as error. */
+ Named_value::free_str(value);
+ return TRUE;
+ }
+
+ escape_mode= FALSE;
+ }
+ else
+ {
+ if (*text == '\\')
+ {
+ escape_mode= TRUE;
+ }
+ else
+ {
+ *v= *text;
+ ++v;
+ }
+ }
+
+ ++text;
+ }
+
+ *v= 0;
+
+ /* "2" below stands for beginning and ending quotes. */
+ *text_len= text - text_start_ptr + 2;
+
+ return FALSE;
+}
+
+
+void skip_spaces(const char **text)
+{
+ while (**text && my_isspace(default_charset_info, **text))
+ ++(*text);
+}
+
+
Command *parse_command(Instance_map *map, const char *text)
{
uint word_len;
- const char *instance_name;
- uint instance_name_len;
- const char *option;
- uint option_len;
- const char *option_value;
- uint option_value_len;
- const char *log_size;
+ LEX_STRING instance_name;
Command *command;
const char *saved_text= text;
- bool skip= false;
- const char *tmp;
Token tok1= shift_token(&text, &word_len);
switch (tok1) {
case TOK_START: // fallthrough
case TOK_STOP:
+ case TOK_CREATE:
+ case TOK_DROP:
if (shift_token(&text, &word_len) != TOK_INSTANCE)
goto syntax_error;
get_word(&text, &word_len);
if (word_len == 0)
goto syntax_error;
- instance_name= text;
- instance_name_len= word_len;
+ instance_name.str= (char *) text;
+ instance_name.length= word_len;
text+= word_len;
- /* it should be the end of command */
- get_word(&text, &word_len, NONSPACE);
- if (word_len)
- goto syntax_error;
- if (tok1 == TOK_START)
- command= new Start_instance(map, instance_name, instance_name_len);
+ if (tok1 == TOK_CREATE)
+ {
+ Create_instance *cmd= new Create_instance(map, &instance_name);
+
+ if (!cmd)
+ return NULL; /* Report ER_OUT_OF_RESOURCES. */
+
+ if (cmd->init(&text))
+ {
+ delete cmd;
+ goto syntax_error;
+ }
+
+ command= cmd;
+ }
else
- command= new Stop_instance(map, instance_name, instance_name_len);
+ {
+ /* it should be the end of command */
+ get_word(&text, &word_len, NONSPACE);
+ if (word_len)
+ goto syntax_error;
+ }
+
+ switch (tok1) {
+ case TOK_START:
+ command= new Start_instance(map, &instance_name);
+ break;
+ case TOK_STOP:
+ command= new Stop_instance(map, &instance_name);
+ break;
+ case TOK_CREATE:
+ ; /* command already initialized. */
+ break;
+ case TOK_DROP:
+ command= new Drop_instance(map, &instance_name);
+ break;
+ default: /* this is impossible, but nevertheless... */
+ DBUG_ASSERT(0);
+ }
break;
case TOK_FLUSH:
if (shift_token(&text, &word_len) != TOK_INSTANCES)
@@ -163,53 +343,28 @@ Command *parse_command(Instance_map *map, const char *text)
command= new Flush_instances(map);
break;
case TOK_UNSET:
- skip= true;
case TOK_SET:
+ {
+ Abstract_option_cmd *cmd;
- if (get_text_id(&text, &instance_name_len, &instance_name))
- goto syntax_error;
- text+= instance_name_len;
-
- /* the next token should be a dot */
- get_word(&text, &word_len);
- if (*text != '.')
- goto syntax_error;
- text++;
+ if (tok1 == TOK_SET)
+ cmd= new Set_option(map);
+ else
+ cmd= new Unset_option(map);
- get_word(&text, &option_len, NONSPACE);
- option= text;
- if ((tmp= strchr(text, '=')) != NULL)
- option_len= tmp - text;
- text+= option_len;
+ if (!cmd)
+ return NULL; /* Report ER_OUT_OF_RESOURCES. */
- get_word(&text, &word_len);
- if (*text == '=')
- {
- text++; /* skip '=' */
- get_word(&text, &option_value_len, NONSPACE);
- option_value= text;
- text+= option_value_len;
- }
- else
- {
- option_value= "";
- option_value_len= 0;
- }
+ if (cmd->init(&text))
+ {
+ delete cmd;
+ goto syntax_error;
+ }
- /* should be empty */
- get_word(&text, &word_len, NONSPACE);
- if (word_len)
- goto syntax_error;
+ command= cmd;
- if (skip)
- command= new Unset_option(map, instance_name, instance_name_len,
- option, option_len, option_value,
- option_value_len);
- else
- command= new Set_option(map, instance_name, instance_name_len,
- option, option_len, option_value,
- option_value_len);
- break;
+ break;
+ }
case TOK_SHOW:
switch (shift_token(&text, &word_len)) {
case TOK_INSTANCES:
@@ -222,30 +377,35 @@ Command *parse_command(Instance_map *map, const char *text)
switch (Token tok2= shift_token(&text, &word_len)) {
case TOK_OPTIONS:
case TOK_STATUS:
- if (get_text_id(&text, &instance_name_len, &instance_name))
+ if (get_text_id(&text, &instance_name))
goto syntax_error;
- text+= instance_name_len;
+ text+= instance_name.length;
/* check that this is the end of the command */
get_word(&text, &word_len, NONSPACE);
if (word_len)
goto syntax_error;
if (tok2 == TOK_STATUS)
- command= new Show_instance_status(map, instance_name,
- instance_name_len);
+ command= new Show_instance_status(map, &instance_name);
else
- command= new Show_instance_options(map, instance_name,
- instance_name_len);
+ command= new Show_instance_options(map, &instance_name);
break;
default:
goto syntax_error;
}
break;
default:
- instance_name= text - word_len;
- instance_name_len= word_len;
- if (instance_name_len)
+ instance_name.str= (char *) text - word_len;
+ instance_name.length= word_len;
+ if (instance_name.length)
{
Log_type log_type;
+
+ long log_size;
+ LEX_STRING log_size_str;
+
+ long log_offset= 0;
+ LEX_STRING log_offset_str= { NULL, 0 };
+
switch (shift_token(&text, &word_len)) {
case TOK_LOG:
switch (Token tok3= shift_token(&text, &word_len)) {
@@ -254,8 +414,7 @@ Command *parse_command(Instance_map *map, const char *text)
/* check that this is the end of the command */
if (word_len)
goto syntax_error;
- command= new Show_instance_log_files(map, instance_name,
- instance_name_len);
+ command= new Show_instance_log_files(map, &instance_name);
break;
case TOK_ERROR:
case TOK_GENERAL:
@@ -275,12 +434,14 @@ Command *parse_command(Instance_map *map, const char *text)
goto syntax_error;
}
/* get the size of the log we want to retrieve */
- if (get_text_id(&text, &word_len, &log_size))
+ if (get_text_id(&text, &log_size_str))
goto syntax_error;
- text+= word_len;
+ text+= log_size_str.length;
+
/* this parameter is required */
- if (!word_len)
+ if (!log_size_str.length)
goto syntax_error;
+
/* the next token should be comma, or nothing */
get_word(&text, &word_len);
switch (*text) {
@@ -290,23 +451,41 @@ Command *parse_command(Instance_map *map, const char *text)
get_word(&text, &word_len);
if (!word_len)
goto syntax_error;
+ log_offset_str.str= (char *) text;
+ log_offset_str.length= word_len;
text+= word_len;
- command= new Show_instance_log(map, instance_name,
- instance_name_len, log_type,
- log_size, text);
get_word(&text, &word_len, NONSPACE);
/* check that this is the end of the command */
if (word_len)
goto syntax_error;
break;
case '\0':
- command= new Show_instance_log(map, instance_name,
- instance_name_len, log_type,
- log_size, NULL);
break; /* this is ok */
default:
+ goto syntax_error;
+ }
+
+ /* Parse size parameter. */
+
+ if (parse_long(&log_size_str, &log_size))
+ goto syntax_error;
+
+ if (log_size <= 0)
goto syntax_error;
+
+ /* Parse offset parameter (if specified). */
+
+ if (log_offset_str.length)
+ {
+ if (parse_long(&log_offset_str, &log_offset))
+ goto syntax_error;
+
+ if (log_offset <= 0)
+ goto syntax_error;
}
+
+ command= new Show_instance_log(map, &instance_name,
+ log_type, log_size, log_offset);
break;
default:
goto syntax_error;
diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h
index 3da53e3a61e..ae29c7eb64a 100644
--- a/server-tools/instance-manager/parse.h
+++ b/server-tools/instance-manager/parse.h
@@ -18,6 +18,7 @@
#include <my_global.h>
#include <my_sys.h>
+#include <m_string.h>
class Command;
class Instance_map;
@@ -29,10 +30,148 @@ enum Log_type
IM_LOG_SLOW
};
-Command *parse_command(Instance_map *instance_map, const char *text);
+Command *parse_command(Instance_map *map, const char *text);
+
+bool parse_option_value(const char *text, uint *text_len, char **value);
+
+void skip_spaces(const char **text);
/* define kinds of the word seek method */
-enum { ALPHANUM= 1, NONSPACE };
+enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME };
+
+/************************************************************************/
+
+class Named_value
+{
+public:
+ /*
+ The purpose of these methods is just to have one method for
+ allocating/deallocating memory for strings for Named_value.
+ */
+
+ static inline char *alloc_str(const LEX_STRING *str);
+ static inline char *alloc_str(const char *str);
+ static inline void free_str(char **str);
+
+public:
+ inline Named_value();
+ inline Named_value(char *name_arg, char *value_arg);
+
+ inline char *get_name();
+ inline char *get_value();
+
+ inline void free();
+
+private:
+ char *name;
+ char *value;
+};
+
+inline char *Named_value::alloc_str(const LEX_STRING *str)
+{
+ return my_strndup((const byte *) str->str, str->length, MYF(0));
+}
+
+inline char *Named_value::alloc_str(const char *str)
+{
+ return my_strdup(str, MYF(0));
+}
+
+inline void Named_value::free_str(char **str)
+{
+ my_free(*str, MYF(MY_ALLOW_ZERO_PTR));
+ *str= NULL;
+}
+
+inline Named_value::Named_value()
+ :name(NULL), value(NULL)
+{ }
+
+inline Named_value::Named_value(char *name_arg, char *value_arg)
+ :name(name_arg), value(value_arg)
+{ }
+
+inline char *Named_value::get_name()
+{
+ return name;
+}
+
+inline char *Named_value::get_value()
+{
+ return value;
+}
+
+void Named_value::free()
+{
+ free_str(&name);
+ free_str(&value);
+}
+
+/************************************************************************/
+
+class Named_value_arr
+{
+public:
+ Named_value_arr();
+ ~Named_value_arr();
+
+ bool init();
+
+ inline int get_size() const;
+ inline Named_value get_element(int idx) const;
+ inline void remove_element(int idx);
+ inline bool add_element(Named_value *option);
+ inline bool replace_element(int idx, Named_value *option);
+
+private:
+ bool initialized;
+ DYNAMIC_ARRAY arr;
+};
+
+
+inline int Named_value_arr::get_size() const
+{
+ return arr.elements;
+}
+
+
+inline Named_value Named_value_arr::get_element(int idx) const
+{
+ DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+ Named_value option;
+ get_dynamic((DYNAMIC_ARRAY *) &arr, (gptr) &option, idx);
+
+ return option;
+}
+
+
+inline void Named_value_arr::remove_element(int idx)
+{
+ DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+ get_element(idx).free();
+
+ delete_dynamic_element(&arr, idx);
+}
+
+
+inline bool Named_value_arr::add_element(Named_value *option)
+{
+ return insert_dynamic(&arr, (gptr) option);
+}
+
+
+inline bool Named_value_arr::replace_element(int idx, Named_value *option)
+{
+ DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+ get_element(idx).free();
+
+ return set_dynamic(&arr, (gptr) option, idx);
+}
+
+/************************************************************************/
/*
tries to find next word in the text
@@ -41,7 +180,7 @@ enum { ALPHANUM= 1, NONSPACE };
*/
inline void get_word(const char **text, uint *word_len,
- int seek_method= ALPHANUM)
+ enum_seek_method seek_method= ALPHANUM)
{
const char *word_end;
@@ -51,13 +190,23 @@ inline void get_word(const char **text, uint *word_len,
word_end= *text;
- if (seek_method == ALPHANUM)
+ switch (seek_method) {
+ case ALPHANUM:
while (my_isalnum(default_charset_info, *word_end))
++word_end;
- else
+ break;
+ case NONSPACE:
while (!my_isspace(default_charset_info, *word_end) &&
(*word_end != '\0'))
++word_end;
+ break;
+ case OPTION_NAME:
+ while (my_isalnum(default_charset_info, *word_end) ||
+ *word_end == '-' ||
+ *word_end == '_')
+ ++word_end;
+ break;
+ }
*word_len= word_end - *text;
}
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
index 64bb6a6485f..643a50625a1 100644
--- a/server-tools/instance-manager/parse_output.cc
+++ b/server-tools/instance-manager/parse_output.cc
@@ -14,13 +14,15 @@
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 "parse.h"
#include "parse_output.h"
-#include <stdio.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+
+#include <stdio.h>
+
+#include "parse.h"
#include "portability.h"
diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h
index 6a84fabbf17..b86363a4452 100644
--- a/server-tools/instance-manager/parse_output.h
+++ b/server-tools/instance-manager/parse_output.h
@@ -16,6 +16,8 @@
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>
+
#define GET_VALUE 1
#define GET_LINE 2
diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h
index 1a3be5705e3..a76cff58893 100644
--- a/server-tools/instance-manager/portability.h
+++ b/server-tools/instance-manager/portability.h
@@ -16,11 +16,25 @@
/*TODO: fix this */
#define PROTOCOL_VERSION 10
+#define DFLT_CONFIG_FILE_NAME "my.ini"
+#define DFLT_MYSQLD_PATH "mysqld"
+#define DFLT_PASSWD_FILE_EXT ".passwd"
+#define DFLT_PID_FILE_EXT ".pid"
+#define DFLT_SOCKET_FILE_EXT ".sock"
+
typedef int pid_t;
#undef popen
#define popen(A,B) _popen(A,B)
+#define NEWLINE "\r\n"
+#define NEWLINE_LEN 2
+
+#else /* ! __WIN__ */
+
+#define NEWLINE "\n"
+#define NEWLINE_LEN 1
+
#endif /* __WIN__ */
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */
diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc
index d2d6a3f636c..d3cc52ec638 100644
--- a/server-tools/instance-manager/priv.cc
+++ b/server-tools/instance-manager/priv.cc
@@ -14,10 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "priv.h"
+
#include <my_global.h>
#include <mysql_com.h>
-#include "priv.h"
-#include "portability.h"
#if defined(__ia64__) || defined(__ia64)
/*
@@ -43,9 +43,7 @@ bool linuxthreads;
The following string must be less then 80 characters, as
mysql_connection.cc relies on it
*/
-const char mysqlmanager_version[] = "0.2-alpha";
-
-const int mysqlmanager_version_length= sizeof(mysqlmanager_version) - 1;
+const LEX_STRING mysqlmanager_version= { C_STRING_WITH_SIZE("1.0-beta") };
const unsigned char protocol_version= PROTOCOL_VERSION;
diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h
index 52d7aa1d23d..0b393c17ac2 100644
--- a/server-tools/instance-manager/priv.h
+++ b/server-tools/instance-manager/priv.h
@@ -16,13 +16,17 @@
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 <m_string.h>
+#include <my_pthread.h>
+
#include <sys/types.h>
-#ifdef __WIN__
-#include "portability.h"
-#else
+
+#ifndef __WIN__
#include <unistd.h>
#endif
-#include "my_pthread.h"
+
+#include "portability.h"
/* IM-wide platform-independent defines */
#define SERVER_DEFAULT_PORT 3306
@@ -31,6 +35,21 @@
/* three-week timeout should be enough */
#define LONG_TIMEOUT ((ulong) 3600L*24L*21L)
+const int MEM_ROOT_BLOCK_SIZE= 512;
+
+/* The maximal length of option name and option value. */
+const int MAX_OPTION_LEN= 1024;
+
+/*
+ The maximal length of whole option string:
+ --<option name>=<option value>
+*/
+const int MAX_OPTION_STR_LEN= 2 + MAX_OPTION_LEN + 1 + MAX_OPTION_LEN + 1;
+
+const int MAX_VERSION_LENGTH= 160;
+
+const int MAX_INSTANCE_NAME_SIZE= FN_REFLEN;
+
/* the pid of the manager process (of the signal thread on the LinuxThreads) */
extern pid_t manager_pid;
@@ -42,8 +61,7 @@ extern pid_t manager_pid;
extern bool linuxthreads;
#endif
-extern const char mysqlmanager_version[];
-extern const int mysqlmanager_version_length;
+extern const LEX_STRING mysqlmanager_version;
/* MySQL client-server protocol version: substituted from configure */
extern const unsigned char protocol_version;
diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc
index 73e07f993ae..4a8c4d0b88d 100644
--- a/server-tools/instance-manager/protocol.cc
+++ b/server-tools/instance-manager/protocol.cc
@@ -163,7 +163,7 @@ int send_fields(struct st_net *net, LIST *fields)
Buffer send_buff;
char small_buff[4];
uint position= 0;
- NAME_WITH_LENGTH *field;
+ LEX_STRING *field;
/* send the number of fileds */
net_store_length(small_buff, (uint) list_length(fields));
@@ -173,7 +173,7 @@ int send_fields(struct st_net *net, LIST *fields)
while (tmp)
{
position= 0;
- field= (NAME_WITH_LENGTH *) tmp->data;
+ field= (LEX_STRING *) tmp->data;
store_to_protocol_packet(&send_buff,
(char*) "", &position); /* catalog name */
@@ -184,9 +184,9 @@ int send_fields(struct st_net *net, LIST *fields)
store_to_protocol_packet(&send_buff,
(char*) "", &position); /* table name alias */
store_to_protocol_packet(&send_buff,
- field->name, &position); /* column name */
+ field->str, &position); /* column name */
store_to_protocol_packet(&send_buff,
- field->name, &position); /* column name alias */
+ field->str, &position); /* column name alias */
send_buff.reserve(position, 12);
if (send_buff.is_error())
goto err;
diff --git a/server-tools/instance-manager/protocol.h b/server-tools/instance-manager/protocol.h
index f38eac6b079..2c84ad394b4 100644
--- a/server-tools/instance-manager/protocol.h
+++ b/server-tools/instance-manager/protocol.h
@@ -20,11 +20,6 @@
#include <my_list.h>
-typedef struct field {
- char *name;
- uint length;
-} NAME_WITH_LENGTH;
-
/* default field length to be used in various field-realted functions */
enum { DEFAULT_FIELD_LENGTH= 20 };
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
index 0091d713a91..a424860548d 100644
--- a/server-tools/instance-manager/thread_registry.cc
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -20,11 +20,12 @@
#include "thread_registry.h"
-#include "log.h"
+#include <my_global.h>
+#include <thr_alarm.h>
-#include <assert.h>
#include <signal.h>
-#include <thr_alarm.h>
+
+#include "log.h"
#ifndef __WIN__
@@ -52,7 +53,7 @@ Thread_info::Thread_info(pthread_t thread_id_arg) :
*/
Thread_registry::Thread_registry() :
- shutdown_in_progress(false)
+ shutdown_in_progress(FALSE)
,sigwait_thread_pid(pthread_self())
{
pthread_mutex_init(&LOCK_thread_registry, 0);
@@ -186,7 +187,7 @@ void Thread_registry::deliver_shutdown()
set_timespec(shutdown_time, 1);
pthread_mutex_lock(&LOCK_thread_registry);
- shutdown_in_progress= true;
+ shutdown_in_progress= TRUE;
#ifndef __WIN__
/* to stop reading from the network we need to flush alarm queue */
diff --git a/server-tools/instance-manager/user_management_commands.cc b/server-tools/instance-manager/user_management_commands.cc
new file mode 100644
index 00000000000..03a3f9814e3
--- /dev/null
+++ b/server-tools/instance-manager/user_management_commands.cc
@@ -0,0 +1,406 @@
+#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
+#pragma implementation
+#endif
+
+#include "user_management_commands.h"
+
+#include "exit_codes.h"
+#include "options.h"
+#include "user_map.h"
+
+/*************************************************************************
+ Module-specific (internal) functions.
+*************************************************************************/
+
+/*
+ The function returns user name. The user name is retrieved from command-line
+ options (if specified) or from console.
+
+ NOTE
+ This function must not be used in user-management command implementations.
+ Use get_user_name() instead.
+
+ SYNOPSYS
+ get_user_name_impl()
+
+ RETURN
+ NULL on error
+ valid pointer on success
+*/
+
+static char *get_user_name_impl()
+{
+ static char user_name_buf[1024];
+ char *ptr;
+
+ if (Options::User_management::user_name)
+ return Options::User_management::user_name;
+
+ printf("Enter user name: ");
+ fflush(stdout);
+
+ if (!fgets(user_name_buf, sizeof (user_name_buf), stdin))
+ return NULL;
+
+ if ((ptr= strchr(user_name_buf, '\n')))
+ *ptr= 0;
+
+ if ((ptr= strchr(user_name_buf, '\r')))
+ *ptr= 0;
+
+ return user_name_buf;
+}
+
+
+/*
+ The function is intended to provide user name for user-management
+ operations. It also checks that length of the specified user name is correct
+ (not empty, not exceeds USERNAME_LENGTH). Report to stderr if something is
+ wrong.
+
+ SYNOPSYS
+ get_user_name()
+ user_name [OUT] on success contains user name
+
+ RETURN
+ TRUE on error
+ FALSE on success
+*/
+
+static bool get_user_name(LEX_STRING *user_name)
+{
+ char *user_name_str= get_user_name_impl();
+
+ if (!user_name_str)
+ {
+ fprintf(stderr, "Error: unable to read user name from stdin.\n");
+ return TRUE;
+ }
+
+ user_name->str= user_name_str;
+ user_name->length= strlen(user_name->str);
+
+ if (user_name->length == 0)
+ {
+ fprintf(stderr, "Error: user name can not be empty.\n");
+ return TRUE;
+ }
+
+ if (user_name->length > USERNAME_LENGTH)
+ {
+ fprintf(stderr, "Error: user name must not exceed %d characters.\n",
+ (int) USERNAME_LENGTH);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ The function is intended to provide password for user-management operations.
+ The password is retrieved from command-line options (if specified) or from
+ console.
+
+ SYNOPSYS
+ get_password()
+
+ RETURN
+ NULL on error
+ valid pointer on success
+*/
+
+static const char *get_password()
+{
+ if (Options::User_management::password)
+ return Options::User_management::password;
+
+ const char *passwd1= get_tty_password("Enter password: ");
+ const char *passwd2= get_tty_password("Re-type password: ");
+
+ if (strcmp(passwd1, passwd2))
+ {
+ fprintf(stderr, "Error: passwords do not match.\n");
+ return 0;
+ }
+
+ return passwd1;
+}
+
+
+/*
+ Load password file into user map.
+
+ SYNOPSYS
+ load_password_file()
+ user_map target user map
+
+ RETURN
+ See exit_codes.h for possible values.
+*/
+
+static int load_password_file(User_map *user_map)
+{
+ int err_code;
+ const char *err_msg;
+
+ if (user_map->init())
+ {
+ fprintf(stderr, "Error: can not initialize user map.\n");
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ if ((err_code= user_map->load(Options::Main::password_file_name, &err_msg)))
+ fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
+
+ return err_code;
+}
+
+
+/*
+ Save user map into password file.
+
+ SYNOPSYS
+ save_password_file()
+ user_map user map
+
+ RETURN
+ See exit_codes.h for possible values.
+*/
+
+static int save_password_file(User_map *user_map)
+{
+ int err_code;
+ const char *err_msg;
+
+ if ((err_code= user_map->save(Options::Main::password_file_name, &err_msg)))
+ fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
+
+ return err_code;
+}
+
+/*************************************************************************
+ Passwd_cmd
+*************************************************************************/
+
+int Passwd_cmd::execute()
+{
+ LEX_STRING user_name;
+ const char *password;
+
+ printf("Creating record for new user.\n");
+
+ if (get_user_name(&user_name))
+ return ERR_CAN_NOT_READ_USER_NAME;
+
+ if (!(password= get_password()))
+ return ERR_CAN_NOT_READ_PASSWORD;
+
+ {
+ User user(&user_name, password);
+
+ printf("%s:%s\n",
+ (const char *) user.user,
+ (const char *) user.scrambled_password);
+ }
+
+ return ERR_OK;
+}
+
+
+/*************************************************************************
+ Add_user_cmd
+*************************************************************************/
+
+int Add_user_cmd::execute()
+{
+ LEX_STRING user_name;
+ const char *password;
+
+ User_map user_map;
+ User *new_user;
+
+ int err_code;
+
+ if (get_user_name(&user_name))
+ return ERR_CAN_NOT_READ_USER_NAME;
+
+ /* Load the password file. */
+
+ if ((err_code= load_password_file(&user_map)) != ERR_OK)
+ return err_code;
+
+ /* Check that the user does not exist. */
+
+ if (user_map.find_user(&user_name))
+ {
+ fprintf(stderr, "Error: user '%s' already exists.\n",
+ (const char *) user_name.str);
+ return ERR_USER_ALREADY_EXISTS;
+ }
+
+ /* Add the user. */
+
+ if (!(password= get_password()))
+ return ERR_CAN_NOT_READ_PASSWORD;
+
+ if (!(new_user= new User(&user_name, password)))
+ return ERR_OUT_OF_MEMORY;
+
+ if (user_map.add_user(new_user))
+ {
+ delete new_user;
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ /* Save the password file. */
+
+ return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+ Drop_user_cmd
+*************************************************************************/
+
+int Drop_user_cmd::execute()
+{
+ LEX_STRING user_name;
+
+ User_map user_map;
+ User *user;
+
+ int err_code;
+
+ if (get_user_name(&user_name))
+ return ERR_CAN_NOT_READ_USER_NAME;
+
+ /* Load the password file. */
+
+ if ((err_code= load_password_file(&user_map)) != ERR_OK)
+ return err_code;
+
+ /* Find the user. */
+
+ user= user_map.find_user(&user_name);
+
+ if (!user)
+ {
+ fprintf(stderr, "Error: user '%s' does not exist.\n",
+ (const char *) user_name.str);
+ return ERR_USER_NOT_FOUND;
+ }
+
+ /* Remove the user (ignore possible errors). */
+
+ user_map.remove_user(user);
+
+ /* Save the password file. */
+
+ return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+ Edit_user_cmd
+*************************************************************************/
+
+int Edit_user_cmd::execute()
+{
+ LEX_STRING user_name;
+ const char *password;
+
+ User_map user_map;
+ User *user;
+
+ int err_code;
+
+ if (get_user_name(&user_name))
+ return ERR_CAN_NOT_READ_USER_NAME;
+
+ /* Load the password file. */
+
+ if ((err_code= load_password_file(&user_map)) != ERR_OK)
+ return err_code;
+
+ /* Find the user. */
+
+ user= user_map.find_user(&user_name);
+
+ if (!user)
+ {
+ fprintf(stderr, "Error: user '%s' does not exist.\n",
+ (const char *) user_name.str);
+ return ERR_USER_NOT_FOUND;
+ }
+
+ /* Modify user's password. */
+
+ if (!(password= get_password()))
+ return ERR_CAN_NOT_READ_PASSWORD;
+
+ user->set_password(password);
+
+ /* Save the password file. */
+
+ return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+ Clean_db_cmd
+*************************************************************************/
+
+int Clean_db_cmd::execute()
+{
+ User_map user_map;
+
+ if (user_map.init())
+ {
+ fprintf(stderr, "Error: can not initialize user map.\n");
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+ Check_db_cmd
+*************************************************************************/
+
+int Check_db_cmd::execute()
+{
+ User_map user_map;
+
+ return load_password_file(&user_map);
+}
+
+
+/*************************************************************************
+ List_users_cmd
+*************************************************************************/
+
+int List_users_cmd::execute()
+{
+ User_map user_map;
+
+ int err_code;
+
+ /* Load the password file. */
+
+ if ((err_code= load_password_file(&user_map)))
+ return err_code;
+
+ /* Print out registered users. */
+
+ {
+ User_map::Iterator it(&user_map);
+ User *user;
+
+ while ((user= it.next()))
+ fprintf(stderr, "%s\n", (const char *) user->user);
+ }
+
+ return ERR_OK;
+}
diff --git a/server-tools/instance-manager/user_management_commands.h b/server-tools/instance-manager/user_management_commands.h
new file mode 100644
index 00000000000..4bf3546f0a6
--- /dev/null
+++ b/server-tools/instance-manager/user_management_commands.h
@@ -0,0 +1,167 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
+
+/*
+ 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
+*/
+
+/*
+ This header contains declarations of classes inteded to support
+ user-management commands (such as add user, get list of users, etc).
+
+ The general idea is to have one interface (pure abstract class) for such a
+ command. Each concrete user-management command is implemented in concrete
+ class, derived from the common interface.
+*/
+
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
+
+/*************************************************************************
+ User_management_cmd -- base class for User-management commands.
+*************************************************************************/
+
+class User_management_cmd
+{
+public:
+ User_management_cmd()
+ { }
+
+ virtual ~User_management_cmd()
+ { }
+
+public:
+ /*
+ Executes user-management command.
+
+ SYNOPSYS
+ execute()
+
+ RETURN
+ See exit_codes.h for possible values.
+ */
+
+ virtual int execute() = 0;
+};
+
+
+/*************************************************************************
+ Passwd_cmd: support for --passwd command-line option.
+*************************************************************************/
+
+class Passwd_cmd : public User_management_cmd
+{
+public:
+ Passwd_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ Add_user_cmd: support for --add-user command-line option.
+*************************************************************************/
+
+class Add_user_cmd : public User_management_cmd
+{
+public:
+ Add_user_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ Drop_user_cmd: support for --drop-user command-line option.
+*************************************************************************/
+
+class Drop_user_cmd : public User_management_cmd
+{
+public:
+ Drop_user_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ Edit_user_cmd: support for --edit-user command-line option.
+*************************************************************************/
+
+class Edit_user_cmd : public User_management_cmd
+{
+public:
+ Edit_user_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ Clean_db_cmd: support for --clean-db command-line option.
+*************************************************************************/
+
+class Clean_db_cmd : public User_management_cmd
+{
+public:
+ Clean_db_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ Check_db_cmd: support for --check-db command-line option.
+*************************************************************************/
+
+class Check_db_cmd : public User_management_cmd
+{
+public:
+ Check_db_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+
+/*************************************************************************
+ List_users_cmd: support for --list-users command-line option.
+*************************************************************************/
+
+class List_users_cmd : public User_management_cmd
+{
+public:
+ List_users_cmd()
+ { }
+
+public:
+ virtual int execute();
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index 9cb15307131..e8128cf015b 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -19,32 +19,32 @@
#endif
#include "user_map.h"
-
-#include <mysql_com.h>
-#include <m_string.h>
-
+#include "exit_codes.h"
#include "log.h"
+#include "portability.h"
-struct User
+User::User(const LEX_STRING *user_name_arg, const char *password)
{
- char user[USERNAME_LENGTH + 1];
- uint8 user_length;
- uint8 salt[SCRAMBLE_LENGTH];
- int init(const char *line);
-};
+ user_length= strmake(user, user_name_arg->str, USERNAME_LENGTH + 1) - user;
+ set_password(password);
+}
int User::init(const char *line)
{
const char *name_begin, *name_end, *password;
- int line_ending_len= 1;
+ int password_length;
if (line[0] == '\'' || line[0] == '"')
{
name_begin= line + 1;
name_end= strchr(name_begin, line[0]);
if (name_end == 0 || name_end[1] != ':')
- goto err;
+ {
+ log_info("Error: invalid format (unmatched quote) of user line (%s).",
+ (const char *) line);
+ return 1;
+ }
password= name_end + 2;
}
else
@@ -52,33 +52,47 @@ int User::init(const char *line)
name_begin= line;
name_end= strchr(name_begin, ':');
if (name_end == 0)
- goto err;
+ {
+ log_info("Error: invalid format (no delimiter) of user line (%s).",
+ (const char *) line);
+ return 1;
+ }
password= name_end + 1;
}
+
user_length= name_end - name_begin;
if (user_length > USERNAME_LENGTH)
- goto err;
-
- /*
- assume that newline characater is present
- we support reading password files that end in \n or \r\n on
- either platform.
- */
- if (password[strlen(password)-2] == '\r')
- line_ending_len= 2;
- if (strlen(password) != (uint) (SCRAMBLED_PASSWORD_CHAR_LENGTH +
- line_ending_len))
- goto err;
+ {
+ log_info("Error: user name is too long (%d). Max length: %d. "
+ "User line: '%s'.",
+ (int) user_length,
+ (int) USERNAME_LENGTH,
+ (const char *) line);
+ return 1;
+ }
+
+ password_length= strlen(password);
+ if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ log_info("Error: password is too long (%d). Max length: %d. ",
+ "User line: '%s'.",
+ (int) password_length,
+ (int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
+ (const char *) line);
+ return 1;
+ }
memcpy(user, name_begin, user_length);
user[user_length]= 0;
+
+ memcpy(scrambled_password, password, password_length);
+ scrambled_password[password_length]= 0;
+
get_salt_from_password(salt, password);
- log_info("loaded user %s", user);
+
+ log_info("loaded user '%s'.", user);
return 0;
-err:
- log_error("error parsing user and password at line %s", line);
- return 1;
}
@@ -101,30 +115,70 @@ static void delete_user(void *u)
C_MODE_END
+void User_map::Iterator::reset()
+{
+ cur_idx= 0;
+}
+
+
+User *User_map::Iterator::next()
+{
+ if (cur_idx < user_map->hash.records)
+ return (User *) hash_element(&user_map->hash, cur_idx++);
+
+ return NULL;
+}
+
+
int User_map::init()
{
enum { START_HASH_SIZE= 16 };
if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_user_key, delete_user, 0))
return 1;
+
+ initialized= TRUE;
+
return 0;
}
+User_map::User_map()
+ :initialized(FALSE)
+{
+}
+
+
User_map::~User_map()
{
- hash_free(&hash);
+ if (initialized)
+ hash_free(&hash);
}
/*
- Load all users from the password file. Must be called once right after
- construction.
- In case of failure, puts error message to the log file and returns 1
+ Load password database.
+
+ SYNOPSYS
+ load()
+ password_file_name [IN] password file path
+ err_msg [OUT] error message
+
+ DESCRIPTION
+ Load all users from the password file. Must be called once right after
+ construction. In case of failure, puts error message to the log file and
+ returns specific error code.
+
+ RETURN
+ 0 on success
+ !0 on error
*/
-int User_map::load(const char *password_file_name)
+int User_map::load(const char *password_file_name, const char **err_msg)
{
+ static const int ERR_MSG_BUF_SIZE = 255;
+ static char err_msg_buf[ERR_MSG_BUF_SIZE];
+
FILE *file;
char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
2 + /* for possible quotes */
@@ -134,33 +188,172 @@ int User_map::load(const char *password_file_name)
User *user;
int rc= 1;
+ if (my_access(password_file_name, F_OK) != 0)
+ {
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "password file (%s) does not exist",
+ (const char *) password_file_name);
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_PASSWORD_FILE_DOES_NOT_EXIST;
+ }
+
if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
{
- /* Probably the password file wasn't specified. Try to leave without it */
- log_info("[WARNING] can't open password file %s: errno=%d, %s", password_file_name,
- errno, strerror(errno));
- return 0;
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "can not open password file (%s): %s",
+ (const char *) password_file_name,
+ (const char *) strerror(errno));
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_IO_ERROR;
}
+ log_info("loading the password database...");
+
while (fgets(line, sizeof(line), file))
{
+ char *user_line= line;
+
+ /*
+ We need to skip EOL-symbols also from the beginning of the line, because
+ if the previous line was ended by \n\r sequence, we get \r in our line.
+ */
+
+ while (user_line[0] == '\r' || user_line[0] == '\n')
+ ++user_line;
+
+ /* Skip EOL-symbols in the end of the line. */
+
+ {
+ char *ptr;
+
+ if ((ptr= strchr(user_line, '\n')))
+ *ptr= 0;
+
+ if ((ptr= strchr(user_line, '\r')))
+ *ptr= 0;
+ }
+
/* skip comments and empty lines */
- if (line[0] == '#' || line[0] == '\n' &&
- (line[1] == '\0' || line[1] == '\r'))
+ if (!user_line[0] || user_line[0] == '#')
continue;
+
if ((user= new User) == 0)
- goto done;
- if (user->init(line) || my_hash_insert(&hash, (byte *) user))
- goto err_init_user;
+ {
+ my_fclose(file, MYF(0));
+
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "out of memory while parsing password file (%s)",
+ (const char *) password_file_name);
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ if (user->init(user_line))
+ {
+ delete user;
+ my_fclose(file, MYF(0));
+
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "password file (%s) corrupted",
+ (const char *) password_file_name);
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_PASSWORD_FILE_CORRUPTED;
+ }
+
+ if (my_hash_insert(&hash, (byte *) user))
+ {
+ delete user;
+ my_fclose(file, MYF(0));
+
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "out of memory while parsing password file (%s)",
+ (const char *) password_file_name);
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_OUT_OF_MEMORY;
+ }
}
- if (feof(file))
- rc= 0;
- goto done;
-err_init_user:
- delete user;
-done:
+
+ log_info("the password database loaded successfully.");
+
my_fclose(file, MYF(0));
- return rc;
+
+ if (err_msg)
+ *err_msg= NULL;
+
+ return ERR_OK;
+}
+
+
+int User_map::save(const char *password_file_name, const char **err_msg)
+{
+ static const int ERR_MSG_BUF_SIZE = 255;
+ static char err_msg_buf[ERR_MSG_BUF_SIZE];
+
+ FILE *file;
+
+ if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY,
+ MYF(0))) == 0)
+ {
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "can not open password file (%s) for writing: %s",
+ (const char *) password_file_name,
+ (const char *) strerror(errno));
+ *err_msg= err_msg_buf;
+ }
+
+ return ERR_IO_ERROR;
+ }
+
+ {
+ User_map::Iterator it(this);
+ User *user;
+
+ while ((user= it.next()))
+ {
+ if (fprintf(file, "%s:%s\n", (const char *) user->user,
+ (const char *) user->scrambled_password) < 0)
+ {
+ if (err_msg)
+ {
+ snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+ "can not write to password file (%s): %s",
+ (const char *) password_file_name,
+ (const char *) strerror(errno));
+ *err_msg= err_msg_buf;
+ }
+
+ my_fclose(file, MYF(0));
+
+ return ERR_IO_ERROR;
+ }
+ }
+ }
+
+ my_fclose(file, MYF(0));
+
+ return ERR_OK;
}
@@ -172,13 +365,33 @@ done:
2 - user not found
*/
-int User_map::authenticate(const char *user_name, uint length,
+int User_map::authenticate(const LEX_STRING *user_name,
const char *scrambled_password,
const char *scramble) const
{
- const User *user= (const User *) hash_search((HASH *) &hash,
- (byte *) user_name, length);
- if (user)
- return check_scramble(scrambled_password, scramble, user->salt);
- return 2;
+ const User *user= find_user(user_name);
+ return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
+}
+
+
+User *User_map::find_user(const LEX_STRING *user_name)
+{
+ return (User*) hash_search(&hash, (byte*) user_name->str, user_name->length);
+}
+
+const User *User_map::find_user(const LEX_STRING *user_name) const
+{
+ return const_cast<User_map *> (this)->find_user(user_name);
+}
+
+
+bool User_map::add_user(User *user)
+{
+ return my_hash_insert(&hash, (byte*) user) == 0 ? FALSE : TRUE;
+}
+
+
+bool User_map::remove_user(User *user)
+{
+ return hash_delete(&hash, (byte*) user) == 0 ? FALSE : TRUE;
}
diff --git a/server-tools/instance-manager/user_map.h b/server-tools/instance-manager/user_map.h
index 4134017dd9b..de207c11e65 100644
--- a/server-tools/instance-manager/user_map.h
+++ b/server-tools/instance-manager/user_map.h
@@ -18,14 +18,35 @@
#include <my_global.h>
-
#include <my_sys.h>
+#include <mysql_com.h>
+#include <m_string.h>
#include <hash.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
+struct User
+{
+ User()
+ {}
+
+ User(const LEX_STRING *user_name_arg, const char *password);
+
+ int init(const char *line);
+
+ inline void set_password(const char *password)
+ {
+ make_scrambled_password(scrambled_password, password);
+ }
+
+ char user[USERNAME_LENGTH + 1];
+ char scrambled_password[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
+ uint8 user_length;
+ uint8 salt[SCRAMBLE_LENGTH];
+};
+
/*
User_map -- all users and passwords
*/
@@ -33,15 +54,51 @@
class User_map
{
public:
+ /* User_map iterator */
+
+ class Iterator
+ {
+ public:
+ Iterator(User_map *user_map_arg) :
+ cur_idx(0), user_map(user_map_arg)
+ { }
+
+ public:
+ void reset();
+
+ User *next();
+
+ private:
+ User_map *user_map;
+ uint cur_idx;
+ };
+
+public:
+ User_map();
~User_map();
int init();
- int load(const char *password_file_name);
- int authenticate(const char *user_name, uint length,
+ int load(const char *password_file_name, const char **err_msg);
+ int save(const char *password_file_name, const char **err_msg);
+ int authenticate(const LEX_STRING *user_name,
const char *scrambled_password,
const char *scramble) const;
+
+ const User *find_user(const LEX_STRING *user_name) const;
+ User *find_user(const LEX_STRING *user_name);
+
+ bool add_user(User *user);
+ bool remove_user(User *user);
+
+private:
+ User_map(const User_map &);
+ User_map &operator =(const User_map &);
+
private:
HASH hash;
+ bool initialized;
+
+ friend class Iterator;
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 05b1efdbe51..2b44fbdcc79 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -51,7 +51,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
- rpl_tblmap.cc sql_binlog.cc event_executor.cc event_timed.cc
+ rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
sql_tablespace.cc event.cc ../sql-common/my_user.c
partition_info.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
diff --git a/sql/Makefile.am b/sql/Makefile.am
index deaf2427aeb..ffc5b2c2573 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -22,7 +22,7 @@ MYSQLBASEdir= $(prefix)
MYSQLLIBdir= $(pkglibdir)
INCLUDES = @ZLIB_INCLUDES@ \
-I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_srcdir)/regex -I$(srcdir) $(yassl_includes) \
+ -I$(top_srcdir)/regex -I$(srcdir) \
$(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
@@ -35,7 +35,7 @@ LDADD = $(top_builddir)/vio/libvio.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/regex/libregex.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
-
+mysqld_DEPENDENCIES= @mysql_plugin_libs@ $(LDADD)
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@pstack_libs@ \
@mysql_plugin_libs@ \
@@ -66,7 +66,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h event.h event_priv.h \
sql_plugin.h authors.h sql_partition.h \
- partition_info.h partition_element.h
+ partition_info.h partition_element.h event_scheduler.h \
+ contributors.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -103,7 +104,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
- event_executor.cc event.cc event_timed.cc \
+ event_scheduler.cc event.cc event_timed.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc
diff --git a/sql/authors.h b/sql/authors.h
index 595d14c6e0b..618c6305f6b 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -57,7 +57,8 @@ struct show_table_authors_st show_table_authors[]= {
{ "Yves Carlier", "", "mysqlaccess" },
{ "Joshua Chamas", "Cupertino, CA, USA",
"Concurrent insert, extended date syntax" },
- { "Petr Chardin", "Moscow, Russia", "Instance Manager (5.0)" },
+ { "Petr Chardin", "Moscow, Russia",
+ "Instance Manager (5.0), Server log tables (5.1)" },
{ "Wei-Jou Chen", "", "Chinese (Big5) character set" },
{ "Albert Chin-A-Young", "",
"Tru64 port, large file support, better TCP wrappers support" },
@@ -73,6 +74,7 @@ struct show_table_authors_st show_table_authors[]= {
{ "Nikolay Grishakin", "Austin, TX, USA", "Testing - Server" },
{ "Wei He", "", "Chinese (GBK) character set" },
{ "Eric Herman", "Amsterdam, Netherlands", "Bug fixing - federated" },
+ { "Andrey Hristov", "Walldorf, Germany", "Event scheduler (5.1)" },
{ "Alexander (Alexi) Ivanov", "St. Petersburg, Russia", "Replication" },
{ "Alexander (Salle) Keremidarski", "Sofia, Bulgaria",
"Bug fixing" },
diff --git a/sql/contributors.h b/sql/contributors.h
new file mode 100644
index 00000000000..dca232b9b69
--- /dev/null
+++ b/sql/contributors.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2005 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 */
+
+/* Structure of the name list */
+
+struct show_table_contributors_st {
+ const char *name;
+ const char *location;
+ const char *comment;
+};
+
+/*
+ Output from "SHOW CONTRIBUTORS"
+
+ Get permission before editing.
+
+ IMPORTANT: Names should be left in historical order.
+
+ Names should be encoded using UTF-8.
+*/
+
+struct show_table_contributors_st show_table_contributors[]= {
+ {"Ronald Bradford", "Brisbane, Australia", "EFF contribution for UC2006 Auction"},
+ {"Sheeri Kritzer", "Boston, Mass. USA", "EFF contribution for UC2006 Auction"},
+ {"Mark Shuttleworth", "London, UK.", "EFF contribution for UC2006 Auction"},
+ {NULL, NULL, NULL}
+};
diff --git a/sql/discover.cc b/sql/discover.cc
index 2a3da55f154..938a05ff4a7 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -119,8 +119,8 @@ int writefrm(const char *name, const void *frmdata, uint len)
{
if (my_write(file,(byte*)frmdata,len,MYF(MY_WME | MY_NABP)))
error= 2;
+ VOID(my_close(file,MYF(0)));
}
- VOID(my_close(file,MYF(0)));
DBUG_RETURN(error);
} /* writefrm */
diff --git a/sql/event.cc b/sql/event.cc
index 4a3c6aad30c..9ca5c62fc1c 100644
--- a/sql/event.cc
+++ b/sql/event.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2005 MySQL AB
+/* Copyright (C) 2004-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
@@ -16,13 +16,12 @@
#include "event_priv.h"
#include "event.h"
+#include "event_scheduler.h"
#include "sp.h"
+#include "sp_head.h"
/*
TODO list :
- - The default value of created/modified should not be 0000-00-00 because of
- STRICT mode restricions.
-
- CREATE EVENT should not go into binary log! Does it now? The SQL statements
issued by the EVENT are replicated.
I have an idea how to solve the problem at failover. So the status field
@@ -32,42 +31,41 @@
should be replicated as disabled. If an event is ALTERed as DISABLED the
query should go untouched into the binary log, when ALTERed as enable then
it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
- TT routines however modify mysql.event internally and this does not go the log
- so in this case queries has to be injected into the log...somehow... or
+ TT routines however modify mysql.event internally and this does not go the
+ log so in this case queries has to be injected into the log...somehow... or
maybe a solution is RBR for this case, because the event may go only from
ENABLED to DISABLED status change and this is safe for replicating. As well
an event may be deleted which is also safe for RBR.
- - Maybe move all allocations during parsing to evex_mem_root thus saving
- double parsing in evex_create_event!
-
- - If the server is killed (stopping) try to kill executing events?
-
- - What happens if one renames an event in the DB while it is in memory?
- Or even deleting it?
-
- - Consider using conditional variable when doing shutdown instead of
- waiting till all worker threads end.
-
- - Make Event_timed::get_show_create_event() work
-
- Add logging to file
- - Move comparison code to class Event_timed
-
Warning:
- - For now parallel execution is not possible because the same sp_head cannot be
- executed few times!!! There is still no lock attached to particular event.
-
+ - For now parallel execution is not possible because the same sp_head cannot
+ be executed few times!!! There is still no lock attached to particular
+ event.
*/
-QUEUE EVEX_EQ_NAME;
MEM_ROOT evex_mem_root;
time_t mysql_event_last_create_time= 0L;
-static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
+const char *event_scheduler_state_names[]=
+ { "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
+
+TYPELIB Events::opt_typelib=
+{
+ array_elements(event_scheduler_state_names)-1,
+ "",
+ event_scheduler_state_names,
+ NULL
+};
+
+
+ulong Events::opt_event_scheduler= 2;
+
+static
+TABLE_FIELD_W_TYPE event_table_fields[Events::FIELD_COUNT] = {
{
{(char *) STRING_WITH_LEN("db")},
{(char *) STRING_WITH_LEN("char(64)")},
@@ -186,41 +184,17 @@ LEX_STRING interval_type_to_name[] = {
};
-
-/*
- Inits the scheduler queue - prioritized queue from mysys/queue.c
-
- Synopsis
- evex_queue_init()
-
- queue - pointer the the memory to be initialized as queue. has to be
- allocated from the caller
-
- Notes
- During initialization the queue is sized for 30 events, and when is full
- will auto extent with 30.
-*/
-
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue)
-{
- if (init_queue_ex(queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
- event_timed_compare_q, NULL, 30 /*auto_extent*/))
- sql_print_error("Insufficient memory to initialize executing queue.");
-}
-
-
/*
Compares 2 LEX strings regarding case.
- Synopsis
+ SYNOPSIS
my_time_compare()
s - first LEX_STRING
t - second LEX_STRING
cs - charset
- RETURNS:
+ RETURN VALUE
-1 - s < t
0 - s == t
1 - s > t
@@ -239,32 +213,26 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
/*
Compares 2 TIME structures
- Synopsis
+ SYNOPSIS
my_time_compare()
a - first TIME
b - second time
- RETURNS:
+ RETURN VALUE
-1 - a < b
0 - a == b
1 - a > b
- Notes
+ NOTES
TIME.second_part is not considered during comparison
*/
int
my_time_compare(TIME *a, TIME *b)
{
-
-#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
- my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
- my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
-#else
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
-#endif
if (a_t > b_t)
return 1;
@@ -276,36 +244,11 @@ my_time_compare(TIME *a, TIME *b)
/*
- Compares the execute_at members of 2 Event_timed instances
-
- Synopsis
- event_timed_compare()
-
- a - first Event_timed object
- b - second Event_timed object
-
- RETURNS:
- -1 - a->execute_at < b->execute_at
- 0 - a->execute_at == b->execute_at
- 1 - a->execute_at > b->execute_at
-
- Notes
- execute_at.second_part is not considered during comparison
-*/
-
-int
-event_timed_compare(Event_timed *a, Event_timed *b)
-{
- return my_time_compare(&a->execute_at, &b->execute_at);
-}
-
-
-/*
Compares the execute_at members of 2 Event_timed instances.
Used as callback for the prioritized queue when shifting
elements inside.
- Synopsis
+ SYNOPSIS
event_timed_compare()
vptr - not used (set it to NULL)
@@ -324,7 +267,8 @@ event_timed_compare(Event_timed *a, Event_timed *b)
int
event_timed_compare_q(void *vptr, byte* a, byte *b)
{
- return event_timed_compare((Event_timed *)a, (Event_timed *)b);
+ return my_time_compare(&((Event_timed *)a)->execute_at,
+ &((Event_timed *)b)->execute_at);
}
@@ -335,8 +279,8 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
YEAR_MONTH - expression is in months
DAY_MINUTE - expression is in minutes
- Synopsis
- event_reconstruct_interval_expression()
+ SYNOPSIS
+ Events::reconstruct_interval_expression()
buf - preallocated String buffer to add the value to
interval - the interval type (for instance YEAR_MONTH)
expression - the value in the lowest entity
@@ -347,9 +291,9 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
*/
int
-event_reconstruct_interval_expression(String *buf,
- interval_type interval,
- longlong expression)
+Events::reconstruct_interval_expression(String *buf,
+ interval_type interval,
+ longlong expression)
{
ulonglong expr= expression;
char tmp_buff[128], *end;
@@ -466,22 +410,23 @@ common_1_lev_code:
Open mysql.event table for read
SYNOPSIS
- evex_open_event_table_for_read()
- thd Thread context
- lock_type How to lock the table
- table The table pointer
+ Events::open_event_table()
+ thd Thread context
+ lock_type How to lock the table
+ table We will store the open table here
- RETURN
+ RETURN VALUE
1 Cannot lock table
2 The table is corrupted - different number of fields
0 OK
*/
int
-evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
+Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
+ TABLE **table)
{
TABLE_LIST tables;
- DBUG_ENTER("open_proc_table");
+ DBUG_ENTER("open_events_table");
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
@@ -491,7 +436,8 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
if (simple_open_n_lock_tables(thd, &tables))
DBUG_RETURN(1);
- if (table_check_intact(tables.table, EVEX_FIELD_COUNT, event_table_fields,
+ if (table_check_intact(tables.table, Events::FIELD_COUNT,
+ event_table_fields,
&mysql_event_last_create_time,
ER_CANNOT_LOAD_FROM_TABLE))
{
@@ -499,7 +445,7 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
DBUG_RETURN(2);
}
*table= tables.table;
-
+ tables.table->use_all_columns();
DBUG_RETURN(0);
}
@@ -510,7 +456,7 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
SYNOPSIS
evex_db_find_event_aux()
thd Thread context
- et evet_timed object containing dbname, name & definer
+ et event_timed object containing dbname & name
table TABLE object for open mysql.event table.
RETURN VALUE
@@ -521,8 +467,7 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
inline int
evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table)
{
- return evex_db_find_event_by_name(thd, et->dbname, et->name,
- et->definer, table);
+ return evex_db_find_event_by_name(thd, et->dbname, et->name, table);
}
@@ -544,7 +489,6 @@ evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table)
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
- const LEX_STRING user_name,
TABLE *table)
{
byte key[MAX_KEY_LENGTH];
@@ -558,50 +502,55 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
'db' and 'name' and the first key is the primary key over the
same fields.
*/
- if (dbname.length > table->field[EVEX_FIELD_DB]->field_length ||
- ev_name.length > table->field[EVEX_FIELD_NAME]->field_length ||
- user_name.length > table->field[EVEX_FIELD_DEFINER]->field_length)
+ if (dbname.length > table->field[Events::FIELD_DB]->field_length ||
+ ev_name.length > table->field[Events::FIELD_NAME]->field_length)
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
- table->field[EVEX_FIELD_DB]->store(dbname.str, dbname.length, &my_charset_bin);
- table->field[EVEX_FIELD_NAME]->store(ev_name.str, ev_name.length,
- &my_charset_bin);
- table->field[EVEX_FIELD_DEFINER]->store(user_name.str, user_name.length,
+ table->field[Events::FIELD_DB]->store(dbname.str, dbname.length,
+ &my_charset_bin);
+ table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length,
&my_charset_bin);
- key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
+ key_copy(key, table->record[0], table->key_info,
+ table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0, key,
- table->key_info->key_length,HA_READ_KEY_EXACT))
+ table->key_info->key_length,
+ HA_READ_KEY_EXACT))
+ {
+ DBUG_PRINT("info", ("Row not found"));
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
+ }
+ DBUG_PRINT("info", ("Row found!"));
DBUG_RETURN(0);
}
/*
- Puts some data common to CREATE and ALTER EVENT into a row.
+ Puts some data common to CREATE and ALTER EVENT into a row.
- SYNOPSIS
- evex_fill_row()
- thd THD
- table the row to fill out
- et Event's data
+ SYNOPSIS
+ evex_fill_row()
+ thd THD
+ table the row to fill out
+ et Event's data
- Returns
- 0 - ok
- EVEX_GENERAL_ERROR - bad data
- EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
+ RETURN VALUE
+ 0 - OK
+ EVEX_GENERAL_ERROR - bad data
+ EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
- DESCRIPTION
- Used both when an event is created and when it is altered.
+ DESCRIPTION
+ Used both when an event is created and when it is altered.
*/
static int
evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
{
- enum evex_table_field field_num;
+ CHARSET_INFO *scs= system_charset_info;
+ enum Events::enum_table_field field_num;
DBUG_ENTER("evex_fill_row");
@@ -609,19 +558,23 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
- if (table->field[field_num= EVEX_FIELD_DB]->
- store(et->dbname.str, et->dbname.length, system_charset_info))
- goto trunc_err;
+ if (table->field[field_num= Events::FIELD_DEFINER]->
+ store(et->definer.str, et->definer.length, scs))
+ goto err_truncate;
+
+ if (table->field[field_num= Events::FIELD_DB]->
+ store(et->dbname.str, et->dbname.length, scs))
+ goto err_truncate;
- if (table->field[field_num= EVEX_FIELD_NAME]->
- store(et->name.str, et->name.length, system_charset_info))
- goto trunc_err;
+ if (table->field[field_num= Events::FIELD_NAME]->
+ store(et->name.str, et->name.length, scs))
+ goto err_truncate;
- /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
- table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion,
- true);
+ /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
+ table->field[Events::FIELD_ON_COMPLETION]->
+ store((longlong)et->on_completion, true);
- table->field[EVEX_FIELD_STATUS]->store((longlong)et->status, true);
+ table->field[Events::FIELD_STATUS]->store((longlong)et->status, true);
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
@@ -629,53 +582,54 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
*/
if (et->body.str)
{
- table->field[EVEX_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode,
- true);
+ table->field[Events::FIELD_SQL_MODE]->
+ store((longlong)thd->variables.sql_mode, true);
- if (table->field[field_num= EVEX_FIELD_BODY]->
- store(et->body.str, et->body.length, system_charset_info))
- goto trunc_err;
+ if (table->field[field_num= Events::FIELD_BODY]->
+ store(et->body.str, et->body.length, scs))
+ goto err_truncate;
}
if (et->expression)
{
- table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
- table->field[EVEX_FIELD_INTERVAL_EXPR]->store((longlong)et->expression,true);
+ table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull();
+ table->field[Events::FIELD_INTERVAL_EXPR]->
+ store((longlong)et->expression, true);
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_notnull();
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_notnull();
/*
In the enum (C) intervals start from 0 but in mysql enum valid values start
from 1. Thus +1 offset is needed!
*/
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1,
- true);
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->
+ store((longlong)et->interval+1, true);
- table->field[EVEX_FIELD_EXECUTE_AT]->set_null();
+ table->field[Events::FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
- table->field[EVEX_FIELD_STARTS]->set_notnull();
- table->field[EVEX_FIELD_STARTS]->
+ table->field[Events::FIELD_STARTS]->set_notnull();
+ table->field[Events::FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
- table->field[EVEX_FIELD_ENDS]->set_notnull();
- table->field[EVEX_FIELD_ENDS]->
+ table->field[Events::FIELD_ENDS]->set_notnull();
+ table->field[Events::FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
}
else if (et->execute_at.year)
{
- table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null();
- table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
- table->field[EVEX_FIELD_STARTS]->set_null();
- table->field[EVEX_FIELD_ENDS]->set_null();
+ table->field[Events::FIELD_INTERVAL_EXPR]->set_null();
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_null();
+ table->field[Events::FIELD_STARTS]->set_null();
+ table->field[Events::FIELD_ENDS]->set_null();
- table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
- table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
- MYSQL_TIMESTAMP_DATETIME);
+ table->field[Events::FIELD_EXECUTE_AT]->set_notnull();
+ table->field[Events::FIELD_EXECUTE_AT]->
+ store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
}
else
{
@@ -686,46 +640,47 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
*/
}
- ((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
+ ((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time();
if (et->comment.str)
{
- if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
- et->comment.length,
- system_charset_info))
- goto trunc_err;
+ if (table->field[field_num= Events::FIELD_COMMENT]->
+ store(et->comment.str, et->comment.length, scs))
+ goto err_truncate;
}
DBUG_RETURN(0);
-trunc_err:
+err_truncate:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
/*
- Creates an event in mysql.event
-
- SYNOPSIS
- db_create_event()
- thd THD
- et Event_timed object containing information for the event
- create_if_not - if an warning should be generated in case event exists
- rows_affected - how many rows were affected
-
- Return value
- 0 - OK
- EVEX_GENERAL_ERROR - Failure
- DESCRIPTION
- Creates an event. Relies on evex_fill_row which is shared with
- db_update_event. The name of the event is inside "et".
+ Creates an event in mysql.event
+
+ SYNOPSIS
+ db_create_event()
+ thd THD
+ et Event_timed object containing information for the event
+ create_if_not If an warning should be generated in case event exists
+ rows_affected How many rows were affected
+
+ RETURN VALUE
+ 0 - OK
+ EVEX_GENERAL_ERROR - Failure
+
+ DESCRIPTION
+ Creates an event. Relies on evex_fill_row which is shared with
+ db_update_event. The name of the event is inside "et".
*/
-static int
+int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected)
{
int ret= 0;
+ CHARSET_INFO *scs= system_charset_info;
TABLE *table;
char olddb[128];
bool dbchanged= false;
@@ -734,7 +689,7 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
*rows_affected= 0;
DBUG_PRINT("info", ("open mysql.event for update"));
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
@@ -755,7 +710,8 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
}
DBUG_PRINT("info", ("non-existant, go forward"));
- if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0, &dbchanged)))
+ if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0,
+ &dbchanged)))
{
my_error(ER_BAD_DB_ERROR, MYF(0));
goto err;
@@ -778,7 +734,7 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
goto err;
}
- if (et->body.length > table->field[EVEX_FIELD_BODY]->field_length)
+ if (et->body.length > table->field[Events::FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
goto err;
@@ -791,15 +747,7 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
goto err;
}
- if ((ret=table->field[EVEX_FIELD_DEFINER]->store(et->definer.str,
- et->definer.length,
- system_charset_info)))
- {
- my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
- goto err;
- }
-
- ((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
+ ((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time();
/*
evex_fill_row() calls my_error() in case of error so no need to
@@ -819,8 +767,8 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
{
thd->clear_error();
/* Such a statement can always go directly to binlog, no trans cache */
- thd->binlog_query(THD::MYSQL_QUERY_TYPE,
- thd->query, thd->query_length, FALSE, FALSE);
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
+ FALSE, FALSE);
}
#endif
@@ -842,33 +790,38 @@ err:
/*
- Used to execute ALTER EVENT. Pendant to evex_update_event().
+ Used to execute ALTER EVENT. Pendant to Events::update_event().
- SYNOPSIS
- db_update_event()
- thd THD
- sp_name the name of the event to alter
- et event's data
+ SYNOPSIS
+ db_update_event()
+ thd THD
+ sp_name the name of the event to alter
+ et event's data
- NOTES
- sp_name is passed since this is the name of the event to
- alter in case of RENAME TO.
+ RETURN VALUE
+ 0 OK
+ EVEX_GENERAL_ERROR Error occured (my_error() called)
+
+ NOTES
+ sp_name is passed since this is the name of the event to
+ alter in case of RENAME TO.
*/
static int
db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
{
+ CHARSET_INFO *scs= system_charset_info;
TABLE *table;
int ret= EVEX_OPEN_TABLE_FAILED;
DBUG_ENTER("db_update_event");
DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
- DBUG_PRINT("enter", ("user: %.*s", et->name.length, et->name.str));
+ DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
if (new_name)
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
new_name->m_name.str));
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
@@ -877,22 +830,21 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
/* first look whether we overwrite */
if (new_name)
{
- if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
- !sortcmp_lex_string(et->dbname, new_name->m_db, system_charset_info))
+ if (!sortcmp_lex_string(et->name, new_name->m_name, scs) &&
+ !sortcmp_lex_string(et->dbname, new_name->m_db, scs))
{
my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
goto err;
}
- if (!evex_db_find_event_by_name(thd, new_name->m_db, new_name->m_name,
- et->definer, table))
+ if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
{
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
goto err;
}
}
/*
- ...and then whether there is such an event. don't exchange the blocks
+ ...and then if there is such an event. Don't exchange the blocks
because you will get error 120 from table handler because new_name will
overwrite the key and SE will tell us that it cannot find the already found
row (copied into record[1] later
@@ -908,16 +860,19 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
/* Don't update create on row update. */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- /* evex_fill_row() calls my_error() in case of error so no need to handle it here */
+ /*
+ evex_fill_row() calls my_error() in case of error so no need to
+ handle it here
+ */
if ((ret= evex_fill_row(thd, table, et, true)))
goto err;
if (new_name)
{
- table->field[EVEX_FIELD_DB]->
- store(new_name->m_db.str, new_name->m_db.length, system_charset_info);
- table->field[EVEX_FIELD_NAME]->
- store(new_name->m_name.str, new_name->m_name.length, system_charset_info);
+ table->field[Events::FIELD_DB]->
+ store(new_name->m_db.str, new_name->m_db.length, scs);
+ table->field[Events::FIELD_NAME]->
+ store(new_name->m_name.str, new_name->m_name.length, scs);
}
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
@@ -938,33 +893,32 @@ err:
/*
- Looks for a named event in mysql.event and in case of success returns
- an object will data loaded from the table.
-
- SYNOPSIS
- db_find_event()
- thd THD
- name the name of the event to find
- definer who owns the event
- ett event's data if event is found
- tbl TABLE object to use when not NULL
-
- NOTES
- 1) Use sp_name for look up, return in **ett if found
- 2) tbl is not closed at exit
-
- RETURN
- 0 ok In this case *ett is set to the event
- # error *ett == 0
+ Looks for a named event in mysql.event and in case of success returns
+ an object will data loaded from the table.
+
+ SYNOPSIS
+ db_find_event()
+ thd THD
+ name the name of the event to find
+ ett event's data if event is found
+ tbl TABLE object to use when not NULL
+
+ NOTES
+ 1) Use sp_name for look up, return in **ett if found
+ 2) tbl is not closed at exit
+
+ RETURN VALUE
+ 0 ok In this case *ett is set to the event
+ # error *ett == 0
*/
-static int
-db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
- TABLE *tbl, MEM_ROOT *root)
+int
+db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
+ MEM_ROOT *root)
{
TABLE *table;
int ret;
- Event_timed *et= 0;
+ Event_timed *et= NULL;
DBUG_ENTER("db_find_event");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
@@ -973,15 +927,14 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
if (tbl)
table= tbl;
- else if (evex_open_event_table(thd, TL_READ, &table))
+ else if (Events::open_event_table(thd, TL_READ, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
ret= EVEX_GENERAL_ERROR;
goto done;
}
- if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, *definer,
- table)))
+ if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table)))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
goto done;
@@ -1015,179 +968,43 @@ done:
/*
- Looks for a named event in mysql.event and then loads it from
- the table, compiles it and insert it into the cache.
-
- SYNOPSIS
- evex_load_and_compile_event()
- thd THD
- spn the name of the event to alter
- definer who is the owner
- use_lock whether to obtain a lock on LOCK_event_arrays or not
-
- RETURN VALUE
- 0 - OK
- < 0 - error (in this case underlying functions call my_error()).
-*/
-
-static int
-evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
- bool use_lock)
-{
- int ret= 0;
- MEM_ROOT *tmp_mem_root;
- Event_timed *ett;
- Open_tables_state backup;
-
- DBUG_ENTER("db_load_and_compile_event");
- DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
-
- tmp_mem_root= thd->mem_root;
- thd->mem_root= &evex_mem_root;
-
- thd->reset_n_backup_open_tables_state(&backup);
- /* no need to use my_error() here because db_find_event() has done it */
- ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
- thd->restore_backup_open_tables_state(&backup);
- if (ret)
- goto done;
-
- ett->compute_next_execution_time();
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) ett);
-
- /*
- There is a copy in the array which we don't need. sphead won't be
- destroyed.
- */
-
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
-done:
- if (thd->mem_root != tmp_mem_root)
- thd->mem_root= tmp_mem_root;
-
- DBUG_RETURN(ret);
-}
+ The function exported to the world for creating of events.
+ SYNOPSIS
+ Events::create_event()
+ thd THD
+ et event's data
+ create_options Options specified when in the query. We are
+ interested whether there is IF NOT EXISTS
+ rows_affected How many rows were affected
-/*
- Removes from queue in memory the event which is identified by the tupple
- (db, name).
-
- SYNOPSIS
- evex_remove_from_cache()
-
- db - db name
- name - event name
- use_lock - whether to lock the mutex LOCK_event_arrays or not in case it
- has been already locked outside
- is_drop - if an event is currently being executed then we can also delete
- the Event_timed instance, so we alarm the event that it should
- drop itself if this parameter is set to TRUE. It's false on
- ALTER EVENT.
-
- RETURNS
- 0 OK (always)
-*/
-
-static int
-evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
- bool is_drop)
-{
- //ToDo : Add definer to the tuple (db, name) to become triple
- uint i;
- int ret= 0;
-
- DBUG_ENTER("evex_remove_from_cache");
- /*
- It is possible that 2 (or 1) pass(es) won't find the event in memory.
- The reason is that DISABLED events are not cached.
- */
-
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
- et->name.str));
- if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
- !sortcmp_lex_string(*db, et->dbname, system_charset_info))
- {
- if (et->can_spawn_now())
- {
- DBUG_PRINT("evex_remove_from_cache", ("not running - free and delete"));
- et->free_sp();
- delete et;
- }
- else
- {
- DBUG_PRINT("evex_remove_from_cache",
- ("running.defer mem free. is_drop=%d", is_drop));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= is_drop;
- }
- DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);
- /* ok, we have cleaned */
- ret= 0;
- goto done;
- }
- }
-
-done:
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
- DBUG_RETURN(ret);
-}
-
+ RETURN VALUE
+ 0 OK
+ !0 Error
-/*
- The function exported to the world for creating of events.
-
- SYNOPSIS
- evex_create_event()
- thd THD
- et event's data
- create_options Options specified when in the query. We are
- interested whether there is IF NOT EXISTS
- rows_affected How many rows were affected
-
- NOTES
- - in case there is an event with the same name (db) and
- IF NOT EXISTS is specified, an warning is put into the W stack.
+ NOTES
+ - in case there is an event with the same name (db) and
+ IF NOT EXISTS is specified, an warning is put into the W stack.
*/
int
-evex_create_event(THD *thd, Event_timed *et, uint create_options,
- uint *rows_affected)
+Events::create_event(THD *thd, Event_timed *et, uint create_options,
+ uint *rows_affected)
{
- int ret = 0;
+ int ret;
- DBUG_ENTER("evex_create_event");
+ DBUG_ENTER("Events::create_event");
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
et->name.str, create_options));
- if ((ret = db_create_event(thd, et,
+ if (!(ret = db_create_event(thd, et,
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
rows_affected)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running && et->status == MYSQL_EVENT_ENABLED)
{
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, et->definer, true);
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() && (ret= scheduler->add_event(thd, et, true)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
/* No need to close the table, it will be closed in sql_parse::do_command */
DBUG_RETURN(ret);
@@ -1195,73 +1012,63 @@ done:
/*
- The function exported to the world for alteration of events.
-
- SYNOPSIS
- evex_update_event()
- thd THD
- et event's data
- new_name set in case of RENAME TO.
-
- NOTES
- et contains data about dbname and event name.
- new_name is the new name of the event, if not null (this means
- that RENAME TO was specified in the query)
+ The function exported to the world for alteration of events.
+
+ SYNOPSIS
+ Events::update_event()
+ thd THD
+ et event's data
+ new_name set in case of RENAME TO.
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
+
+ NOTES
+ et contains data about dbname and event name.
+ new_name is the new name of the event, if not null (this means
+ that RENAME TO was specified in the query)
*/
int
-evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
- uint *rows_affected)
+Events::update_event(THD *thd, Event_timed *et, sp_name *new_name,
+ uint *rows_affected)
{
int ret;
- bool need_second_pass= true;
- DBUG_ENTER("evex_update_event");
+ DBUG_ENTER("Events::update_event");
DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
-
/*
db_update_event() opens & closes the table to prevent
crash later in the code when loading and compiling the new definition.
Also on error conditions my_error() is called so no need to handle here
*/
- if ((ret= db_update_event(thd, et, new_name)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- evex_remove_from_cache(&et->dbname, &et->name, false, false);
- if (et->status == MYSQL_EVENT_ENABLED)
+ if (!(ret= db_update_event(thd, et, new_name)))
{
- if (new_name)
- ret= evex_load_and_compile_event(thd, new_name, et->definer, false);
- else
- {
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, et->definer, false);
- }
- if (ret == EVEX_COMPILE_ERROR)
- my_error(ER_EVENT_COMPILE_ERROR, MYF(0));
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() &&
+ (ret= scheduler->replace_event(thd, et,
+ new_name? &new_name->m_db: NULL,
+ new_name? &new_name->m_name: NULL)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
DBUG_RETURN(ret);
}
/*
- Drops an event
-
- SYNOPSIS
- db_drop_event()
- thd THD
- et event's name
- drop_if_exists if set and the event not existing => warning onto the stack
- rows_affected affected number of rows is returned heres
+ Drops an event
+
+ SYNOPSIS
+ db_drop_event()
+ thd THD
+ et event's name
+ drop_if_exists if set and the event not existing => warning onto the stack
+ rows_affected affected number of rows is returned heres
+
+ RETURN VALUE
+ 0 OK
+ !0 Error (my_error() called)
*/
int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
@@ -1275,7 +1082,7 @@ int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
ret= EVEX_OPEN_TABLE_FAILED;
thd->reset_n_backup_open_tables_state(&backup);
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto done;
@@ -1315,58 +1122,53 @@ done:
/*
- Drops an event
-
- SYNOPSIS
- evex_drop_event()
- thd THD
- et event's name
- drop_if_exists if set and the event not existing => warning onto the stack
- rows_affected affected number of rows is returned heres
-
+ Drops an event
+
+ SYNOPSIS
+ Events::drop_event()
+ thd THD
+ et event's name
+ drop_if_exists if set and the event not existing => warning onto the stack
+ rows_affected affected number of rows is returned heres
+
+ RETURN VALUE
+ 0 OK
+ !0 Error (reported)
*/
int
-evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected)
+Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+ uint *rows_affected)
{
- int ret= 0;
-
- DBUG_ENTER("evex_drop_event");
-
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running)
- ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
+ int ret;
- if (ret == 1)
- ret= 0;
- else if (ret == 0)
- ret= db_drop_event(thd, et, drop_if_exists, rows_affected);
- else
- my_error(ER_UNKNOWN_ERROR, MYF(0));
+ DBUG_ENTER("Events::drop_event");
+ if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected)))
+ {
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized() && (ret= scheduler->drop_event(thd, et)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+ }
DBUG_RETURN(ret);
}
/*
- SHOW CREATE EVENT
+ SHOW CREATE EVENT
- SYNOPSIS
- evex_show_create_event()
- thd THD
- spn the name of the event (db, name)
- definer the definer of the event
+ SYNOPSIS
+ Events::show_create_event()
+ thd THD
+ spn the name of the event (db, name)
- RETURNS
- 0 - OK
- 1 - Error during writing to the wire
+ RETURN VALUE
+ 0 OK
+ 1 Error during writing to the wire
*/
int
-evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
+Events::show_create_event(THD *thd, sp_name *spn)
{
int ret;
Event_timed *et= NULL;
@@ -1376,10 +1178,10 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
thd->reset_n_backup_open_tables_state(&backup);
- ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root);
+ ret= db_find_event(thd, spn, &et, NULL, thd->mem_root);
thd->restore_backup_open_tables_state(&backup);
- if (et)
+ if (!ret)
{
Protocol *protocol= thd->protocol;
char show_str_buf[768];
@@ -1389,12 +1191,10 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
ulong sql_mode_len=0;
show_str.length(0);
+ show_str.set_charset(system_charset_info);
if (et->get_create_event(thd, &show_str))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
field_list.push_back(new Item_empty_string("Event", NAME_LEN));
@@ -1408,201 +1208,218 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
show_str.length()));
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
+
protocol->prepare_for_resend();
protocol->store(et->name.str, et->name.length, system_charset_info);
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(show_str.ptr(), show_str.length(), system_charset_info);
+ protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
ret= protocol->write();
send_eof(thd);
- delete et;
}
-
+ delete et;
DBUG_RETURN(ret);
+err:
+ delete et;
+ DBUG_RETURN(1);
}
/*
- evex_drop_db_events - Drops all events in the selected database
+ Drops all events from a schema
- thd - Thread
- db - ASCIIZ the name of the database
-
- Returns:
- 0 - OK
- 1 - Failed to delete a specific row
- 2 - Got NULL while reading db name from a row
-
- Note:
- The algo is the following
- 1. Go through the in-memory cache, if the scheduler is working
- and for every event whose dbname matches the database we drop
- check whether is currently in execution:
- - Event_timed::can_spawn() returns true -> the event is not
- being executed in a child thread. The reason not to use
- Event_timed::is_running() is that the latter shows only if
- it is being executed, which is 99% of the time in the thread
- but there are some initiliazations before and after the
- anonymous SP is being called. So if we delete in this moment
- -=> *boom*, so we have to check whether the thread has been
- spawned and can_spawn() is the right method.
- - Event_timed::can_spawn() returns false -> being runned ATM
- just set the flags so it should drop itself.
+ SYNOPSIS
+ Events::drop_schema_events()
+ thd Thread
+ db ASCIIZ schema name
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
*/
int
-evex_drop_db_events(THD *thd, char *db)
+Events::drop_schema_events(THD *thd, char *db)
{
- TABLE *table;
- READ_RECORD read_record_info;
int ret= 0;
- uint i;
LEX_STRING db_lex= {db, strlen(db)};
DBUG_ENTER("evex_drop_db_events");
- DBUG_PRINT("info",("dropping events from %s", db));
+ DBUG_PRINT("enter", ("dropping events from %s", db));
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized())
+ ret= scheduler->drop_schema_events(thd, &db_lex);
+ else
+ ret= db_drop_events_from_table(thd, &db_lex);
- if ((ret= evex_open_event_table(thd, TL_WRITE, &table)))
- {
- sql_print_error("Table mysql.event is damaged.");
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
+ DBUG_RETURN(ret);
+}
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- goto skip_memory;
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- if (sortcmp_lex_string(et->dbname, db_lex, system_charset_info))
- continue;
+/*
+ Drops all events in the selected database, from mysql.event.
- if (et->can_spawn_now_n_lock(thd))
- {
- DBUG_PRINT("info",("event %s not running - direct delete", et->name.str));
- if (!(ret= evex_db_find_event_aux(thd, et, table)))
- {
- DBUG_PRINT("info",("event %s found on disk", et->name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- sql_print_error("Error while deleting a row - dropping "
- "a database. Skipping the rest.");
- my_error(ER_EVENT_DROP_FAILED, MYF(0), et->name.str);
- goto end;
- }
- DBUG_PRINT("info",("deleted event [%s] num [%d]. Time to free mem",
- et->name.str, i));
- }
- else if (ret == EVEX_KEY_NOT_FOUND)
- {
- sql_print_error("Expected to find event %s.%s of %s on disk-not there.",
- et->dbname.str, et->name.str, et->definer.str);
- }
- et->free_sp();
- delete et;
- et= 0;
- /* no need to call et->spawn_unlock because we already cleaned et */
- }
- else
- {
- DBUG_PRINT("info",("event %s is running. setting exec_no_more and dropped",
- et->name.str));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= TRUE;
- }
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- /*
- decrease so we start at the same position, there will be
- less elements in the queue, it will still be ordered so on
- next iteration it will be again i the current element or if
- no more we finish.
- */
- --i;
- }
+ SYNOPSIS
+ evex_drop_db_events_from_table()
+ thd Thread
+ db Schema name
-skip_memory:
- /*
- The reasoning behind having two loops is the following:
- If there was only one loop, the table-scan, then for every element which
- matches, the queue in memory has to be searched to remove the element.
- While if we go first over the queue and remove what's in there we have only
- one pass over it and after finishing it, moving to table-scan for the disabled
- events. This needs quite less time and means quite less locking on
- LOCK_event_arrays.
- */
- DBUG_PRINT("info",("Mem-cache checked, now going to db for disabled events"));
+ RETURN VALUE
+ 0 OK
+ !0 Error from ha_delete_row
+*/
+
+int
+db_drop_events_from_table(THD *thd, LEX_STRING *db)
+{
+ int ret;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ DBUG_ENTER("db_drop_events_from_table");
+ DBUG_PRINT("info", ("dropping events from %s", db->str));
+
+ if ((ret= Events::open_event_table(thd, TL_WRITE, &table)))
+ {
+ if (my_errno != ENOENT)
+ sql_print_error("Table mysql.event is damaged. Got error %d on open",
+ my_errno);
+ DBUG_RETURN(ret);
+ }
/* only enabled events are in memory, so we go now and delete the rest */
- init_read_record(&read_record_info, thd, table ,NULL,1,0);
+ init_read_record(&read_record_info, thd, table, NULL, 1, 0);
while (!(read_record_info.read_record(&read_record_info)) && !ret)
{
- char *et_db;
+ char *et_db= get_field(thd->mem_root,
+ table->field[Events::FIELD_DB]);
- if ((et_db= get_field(thd->mem_root, table->field[EVEX_FIELD_DB])) == NULL)
- {
- ret= 2;
- break;
- }
-
LEX_STRING et_db_lex= {et_db, strlen(et_db)};
- if (!sortcmp_lex_string(et_db_lex, db_lex, system_charset_info))
+ DBUG_PRINT("info", ("Current event %s.%s", et_db,
+ get_field(thd->mem_root,
+ table->field[Events::FIELD_NAME])));
+
+ if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info))
{
- Event_timed ett;
- char *ptr;
-
- if ((ptr= get_field(thd->mem_root, table->field[EVEX_FIELD_STATUS]))
- == NullS)
- {
- sql_print_error("Error while loading from mysql.event. "
- "Table probably corrupted");
- goto end;
- }
- /*
- When not running nothing is in memory so we have to clean
- everything.
- We don't delete EVENT_ENABLED events when the scheduler is running
- because maybe this is an event which we asked to drop itself when
- it is finished and it hasn't finished yet, so we don't touch it.
- It will drop itself. The not running ENABLED events has been already
- deleted from ha_delete_row() above in the loop over the QUEUE
- (in case the executor is running).
- 'D' stands for DISABLED, 'E' for ENABLED - it's an enum
- */
- if ((evex_is_running && ptr[0] == 'D') || !evex_is_running)
- {
- DBUG_PRINT("info", ("Dropping %s.%s", et_db, ett.name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- my_error(ER_EVENT_DROP_FAILED, MYF(0), ett.name.str);
- goto end;
- }
- }
+ DBUG_PRINT("info", ("Dropping"));
+ if ((ret= table->file->ha_delete_row(table->record[0])))
+ my_error(ER_EVENT_DROP_FAILED, MYF(0),
+ get_field(thd->mem_root,
+ table->field[Events::FIELD_NAME]));
}
}
- DBUG_PRINT("info",("Disk checked for disabled events. Finishing."));
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
-
thd->version--; /* Force close to free memory */
close_thread_tables(thd);
DBUG_RETURN(ret);
}
+
+
+
+/*
+ Inits the scheduler's structures.
+
+ SYNOPSIS
+ Events::init()
+
+ NOTES
+ This function is not synchronized.
+
+ RETURN VALUE
+ 0 OK
+ 1 Error
+*/
+
+int
+Events::init()
+{
+ int ret= 0;
+ DBUG_ENTER("Events::init");
+
+ /* it should be an assignment! */
+ if (opt_event_scheduler)
+ {
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
+ DBUG_RETURN(scheduler->init() ||
+ (opt_event_scheduler == 1? scheduler->start():
+ scheduler->start_suspended()));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Cleans up scheduler's resources. Called at server shutdown.
+
+ SYNOPSIS
+ Events::shutdown()
+
+ NOTES
+ This function is not synchronized.
+*/
+
+void
+Events::shutdown()
+{
+ DBUG_ENTER("Events::shutdown");
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ if (scheduler->initialized())
+ {
+ scheduler->stop();
+ scheduler->destroy();
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Proxy for Event_scheduler::dump_internal_status
+
+ SYNOPSIS
+ Events::dump_internal_status()
+ thd Thread
+
+ RETURN VALUE
+ 0 OK
+ !0 Error
+*/
+
+int
+Events::dump_internal_status(THD *thd)
+{
+ return Event_scheduler::dump_internal_status(thd);
+}
+
+
+/*
+ Inits Events mutexes
+
+ SYNOPSIS
+ Events::init_mutexes()
+ thd Thread
+*/
+
+void
+Events::init_mutexes()
+{
+ Event_scheduler::init_mutexes();
+}
+
+
+/*
+ Destroys Events mutexes
+
+ SYNOPSIS
+ Events::destroy_mutexes()
+*/
+
+void
+Events::destroy_mutexes()
+{
+ Event_scheduler::destroy_mutexes();
+}
diff --git a/sql/event.h b/sql/event.h
index 27de8b46e32..02c5fa78150 100644
--- a/sql/event.h
+++ b/sql/event.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2004-2005 MySQL AB
+#ifndef _EVENT_H_
+#define _EVENT_H_
+/* Copyright (C) 2004-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
@@ -14,66 +16,109 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef _EVENT_H_
-#define _EVENT_H_
-#include "sp.h"
-#include "sp_head.h"
-
-#define EVEX_OK SP_OK
-#define EVEX_KEY_NOT_FOUND SP_KEY_NOT_FOUND
-#define EVEX_OPEN_TABLE_FAILED SP_OPEN_TABLE_FAILED
-#define EVEX_WRITE_ROW_FAILED SP_WRITE_ROW_FAILED
-#define EVEX_DELETE_ROW_FAILED SP_DELETE_ROW_FAILED
-#define EVEX_GET_FIELD_FAILED SP_GET_FIELD_FAILED
-#define EVEX_PARSE_ERROR SP_PARSE_ERROR
-#define EVEX_INTERNAL_ERROR SP_INTERNAL_ERROR
-#define EVEX_NO_DB_ERROR SP_NO_DB_ERROR
+
+#define EVEX_OK 0
+#define EVEX_KEY_NOT_FOUND -1
+#define EVEX_OPEN_TABLE_FAILED -2
+#define EVEX_WRITE_ROW_FAILED -3
+#define EVEX_DELETE_ROW_FAILED -4
+#define EVEX_GET_FIELD_FAILED -5
+#define EVEX_PARSE_ERROR -6
+#define EVEX_INTERNAL_ERROR -7
+#define EVEX_NO_DB_ERROR -8
#define EVEX_COMPILE_ERROR -19
#define EVEX_GENERAL_ERROR -20
-#define EVEX_BAD_IDENTIFIER SP_BAD_IDENTIFIER
-#define EVEX_BODY_TOO_LONG SP_BODY_TOO_LONG
-#define EVEX_BAD_PARAMS -21
-#define EVEX_NOT_RUNNING -22
-#define EVEX_MICROSECOND_UNSUP -23
+#define EVEX_BAD_IDENTIFIER -21
+#define EVEX_BODY_TOO_LONG -22
+#define EVEX_BAD_PARAMS -23
+#define EVEX_NOT_RUNNING -24
+#define EVEX_MICROSECOND_UNSUP -25
+#define EVEX_CANT_KILL -26
#define EVENT_EXEC_NO_MORE (1L << 0)
#define EVENT_NOT_USED (1L << 1)
+#define EVENT_FREE_WHEN_FINISHED (1L << 2)
-extern ulong opt_event_executor;
+class Event_timed;
-enum enum_event_on_completion
+class Events
{
- MYSQL_EVENT_ON_COMPLETION_DROP = 1,
- MYSQL_EVENT_ON_COMPLETION_PRESERVE
-};
+public:
+ static ulong opt_event_scheduler;
+ static TYPELIB opt_typelib;
-enum enum_event_status
-{
- MYSQL_EVENT_ENABLED = 1,
- MYSQL_EVENT_DISABLED
+ enum enum_table_field
+ {
+ FIELD_DB = 0,
+ FIELD_NAME,
+ FIELD_BODY,
+ FIELD_DEFINER,
+ FIELD_EXECUTE_AT,
+ FIELD_INTERVAL_EXPR,
+ FIELD_TRANSIENT_INTERVAL,
+ FIELD_CREATED,
+ FIELD_MODIFIED,
+ FIELD_LAST_EXECUTED,
+ FIELD_STARTS,
+ FIELD_ENDS,
+ FIELD_STATUS,
+ FIELD_ON_COMPLETION,
+ FIELD_SQL_MODE,
+ FIELD_COMMENT,
+ FIELD_COUNT /* a cool trick to count the number of fields :) */
+ };
+
+ static int
+ create_event(THD *thd, Event_timed *et, uint create_options,
+ uint *rows_affected);
+
+ static int
+ update_event(THD *thd, Event_timed *et, sp_name *new_name,
+ uint *rows_affected);
+
+ static int
+ drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+ uint *rows_affected);
+
+ static int
+ open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
+
+ static int
+ show_create_event(THD *thd, sp_name *spn);
+
+ static int
+ reconstruct_interval_expression(String *buf, interval_type interval,
+ longlong expression);
+
+ static int
+ drop_schema_events(THD *thd, char *db);
+
+ static int
+ dump_internal_status(THD *thd);
+
+ static int
+ init();
+
+ static void
+ shutdown();
+
+ static void
+ init_mutexes();
+
+ static void
+ destroy_mutexes();
+
+
+private:
+ /* Prevent use of these */
+ Events(const Events &);
+ void operator=(Events &);
};
-enum evex_table_field
-{
- EVEX_FIELD_DB = 0,
- EVEX_FIELD_NAME,
- EVEX_FIELD_BODY,
- EVEX_FIELD_DEFINER,
- EVEX_FIELD_EXECUTE_AT,
- EVEX_FIELD_INTERVAL_EXPR,
- EVEX_FIELD_TRANSIENT_INTERVAL,
- EVEX_FIELD_CREATED,
- EVEX_FIELD_MODIFIED,
- EVEX_FIELD_LAST_EXECUTED,
- EVEX_FIELD_STARTS,
- EVEX_FIELD_ENDS,
- EVEX_FIELD_STATUS,
- EVEX_FIELD_ON_COMPLETION,
- EVEX_FIELD_SQL_MODE,
- EVEX_FIELD_COMMENT,
- EVEX_FIELD_COUNT /* a cool trick to count the number of fields :) */
-} ;
+
+
+class sp_head;
class Event_timed
{
@@ -82,12 +127,26 @@ class Event_timed
my_bool in_spawned_thread;
ulong locked_by_thread_id;
my_bool running;
+ ulong thread_id;
pthread_mutex_t LOCK_running;
+ pthread_cond_t COND_finished;
bool status_changed;
bool last_executed_changed;
public:
+ enum enum_status
+ {
+ ENABLED = 1,
+ DISABLED
+ };
+
+ enum enum_on_completion
+ {
+ ON_COMPLETION_DROP = 1,
+ ON_COMPLETION_PRESERVE
+ };
+
TIME last_executed;
LEX_STRING dbname;
@@ -111,8 +170,8 @@ public:
ulonglong created;
ulonglong modified;
- enum enum_event_on_completion on_completion;
- enum enum_event_status status;
+ enum enum_on_completion on_completion;
+ enum enum_status status;
sp_head *sphead;
ulong sql_mode;
const uchar *body_begin;
@@ -153,36 +212,15 @@ public:
DBUG_ASSERT(0);
}
+ Event_timed();
- Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
- running(0), status_changed(false),
- last_executed_changed(false), expression(0), created(0),
- modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
- status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
- body_begin(0), dropped(false),
- free_sphead_on_delete(true), flags(0)
-
- {
- pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
- init();
- }
-
- ~Event_timed()
- {
- deinit_mutexes();
-
- if (free_sphead_on_delete)
- free_sp();
- }
+ ~Event_timed();
void
init();
-
+
void
- deinit_mutexes()
- {
- pthread_mutex_destroy(&this->LOCK_running);
- }
+ deinit_mutexes();
int
init_definer(THD *thd);
@@ -214,12 +252,12 @@ public:
bool
compute_next_execution_time();
- void
- mark_last_executed(THD *thd);
-
int
drop(THD *thd);
+ void
+ mark_last_executed(THD *thd);
+
bool
update_fields(THD *thd);
@@ -227,142 +265,32 @@ public:
get_create_event(THD *thd, String *buf);
int
- execute(THD *thd, MEM_ROOT *mem_root= NULL);
+ execute(THD *thd, MEM_ROOT *mem_root);
int
- compile(THD *thd, MEM_ROOT *mem_root= NULL);
-
- my_bool
- is_running()
- {
- my_bool ret;
-
- VOID(pthread_mutex_lock(&this->LOCK_running));
- ret= running;
- VOID(pthread_mutex_unlock(&this->LOCK_running));
-
- return ret;
- }
-
- /*
- Checks whether the object is being used in a spawned thread.
- This method is for very basic checking. Use ::can_spawn_now_n_lock()
- for most of the cases.
- */
-
- my_bool
- can_spawn_now()
- {
- my_bool ret;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- ret= !in_spawned_thread;
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
- }
+ compile(THD *thd, MEM_ROOT *mem_root);
- /*
- Checks whether this thread can lock the object for modification ->
- preventing being spawned for execution, and locks if possible.
- use ::can_spawn_now() only for basic checking because a race
- condition may occur between the check and eventual modification (deletion)
- of the object.
- */
-
- my_bool
- can_spawn_now_n_lock(THD *thd);
-
- int
- spawn_unlock(THD *thd);
+ bool
+ is_running();
int
- spawn_now(void * (*thread_func)(void*));
+ spawn_now(void * (*thread_func)(void*), void *arg);
- void
+ bool
spawn_thread_finish(THD *thd);
void
- free_sp()
- {
- delete sphead;
- sphead= 0;
- }
-protected:
+ free_sp();
+
bool
- change_security_context(THD *thd, Security_context *s_ctx,
- Security_context **backup);
+ has_equal_db(Event_timed *etn);
+
+ int
+ kill_thread(THD *thd);
void
- restore_security_context(THD *thd, Security_context *backup);
+ set_thread_id(ulong tid) { thread_id= tid; }
};
-int
-evex_create_event(THD *thd, Event_timed *et, uint create_options,
- uint *rows_affected);
-
-int
-evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
- uint *rows_affected);
-
-int
-evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected);
-
-int
-evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
-
-int
-evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer);
-
-int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
-
-int
-event_reconstruct_interval_expression(String *buf,
- interval_type interval,
- longlong expression);
-
-int
-evex_drop_db_events(THD *thd, char *db);
-
-
-int
-init_events();
-
-void
-shutdown_events();
-
-
-// auxiliary
-int
-event_timed_compare(Event_timed **a, Event_timed **b);
-
-
-
-/*
-CREATE TABLE event (
- db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- name char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- body longblob NOT NULL,
- definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- execute_at DATETIME default NULL,
- interval_value int(11) default NULL,
- interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK',
- 'SECOND','MICROSECOND', 'YEAR_MONTH','DAY_HOUR',
- 'DAY_MINUTE','DAY_SECOND',
- 'HOUR_MINUTE','HOUR_SECOND',
- 'MINUTE_SECOND','DAY_MICROSECOND',
- 'HOUR_MICROSECOND','MINUTE_MICROSECOND',
- 'SECOND_MICROSECOND') default NULL,
- created TIMESTAMP NOT NULL,
- modified TIMESTAMP NOT NULL,
- last_executed DATETIME default NULL,
- starts DATETIME default NULL,
- ends DATETIME default NULL,
- status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED',
- on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP',
- comment varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
- PRIMARY KEY (definer,db,name)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
-*/
-
#endif /* _EVENT_H_ */
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index 21464dd777b..f236fb47771 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -13,998 +13,3 @@
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 "event_priv.h"
-#include "event.h"
-#include "sp.h"
-
-#define WAIT_STATUS_READY 0
-#define WAIT_STATUS_EMPTY_QUEUE 1
-#define WAIT_STATUS_NEW_TOP_EVENT 2
-#define WAIT_STATUS_STOP_EXECUTOR 3
-
-
-/*
- Make this define DBUG_FAULTY_THR to be able to put breakpoints inside
- code used by the scheduler's thread(s). In this case user connections
- are not possible because the scheduler thread code is ran inside the
- main thread (no spawning takes place. If you want to debug client
- connection then start with --one-thread and make the define
- DBUG_FAULTY_THR !
-*/
-#define DBUG_FAULTY_THR2
-
-extern ulong thread_created;
-extern const char *my_localhost;
-extern pthread_attr_t connection_attrib;
-
-pthread_mutex_t LOCK_event_arrays, // mutex for when working with the queue
- LOCK_workers_count, // mutex for when inc/dec uint workers_count
- LOCK_evex_running; // mutes for managing bool evex_is_running
-
-static pthread_mutex_t LOCK_evex_main_thread; // mutex for when working with the queue
-bool scheduler_main_thread_running= false;
-
-bool evex_is_running= false;
-
-ulonglong evex_main_thread_id= 0;
-ulong opt_event_executor;
-my_bool event_executor_running_global_var;
-static my_bool evex_mutexes_initted= FALSE;
-static uint workers_count;
-
-static int
-evex_load_events_from_db(THD *thd);
-
-bool
-evex_print_warnings(THD *thd, Event_timed *et);
-
-/*
- TODO Andrey: Check for command line option whether to start
- the main thread or not.
-*/
-
-pthread_handler_t
-event_executor_worker(void *arg);
-
-pthread_handler_t
-event_executor_main(void *arg);
-
-
-/*
- Returns the seconds difference of 2 TIME structs
-
- SYNOPSIS
- evex_time_diff()
- a - TIME struct 1
- b - TIME struct 2
-
- Returns:
- the seconds difference
-*/
-
-static int
-evex_time_diff(TIME *a, TIME *b)
-{
- return sec_since_epoch_TIME(a) - sec_since_epoch_TIME(b);
-}
-
-
-/*
- Inits the mutexes used by the scheduler module
-
- SYNOPSIS
- evex_init_mutexes()
-
- NOTES
- The mutexes are :
- LOCK_event_arrays
- LOCK_workers_count
- LOCK_evex_running
-*/
-
-static void
-evex_init_mutexes()
-{
- if (evex_mutexes_initted)
- return;
-
- evex_mutexes_initted= TRUE;
- pthread_mutex_init(&LOCK_event_arrays, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_workers_count, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_evex_running, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_evex_main_thread, MY_MUTEX_INIT_FAST);
-
- event_executor_running_global_var= opt_event_executor;
-}
-
-extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
-extern time_t mysql_db_table_last_check;
-
-/*
- Opens mysql.db and mysql.user and checks whether
- 1. mysql.db has column Event_priv at column 20 (0 based);
- 2. mysql.user has column Event_priv at column 29 (0 based);
-
- Synopsis
- evex_check_system_tables()
-*/
-
-void
-evex_check_system_tables()
-{
- THD *thd= current_thd;
- TABLE_LIST tables;
- Open_tables_state backup;
-
- /* thd is 0x0 during boot of the server. Later it's !=0x0 */
- if (!thd)
- return;
-
- thd->reset_n_backup_open_tables_state(&backup);
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "db";
- tables.lock_type= TL_READ;
-
- if (simple_open_n_lock_tables(thd, &tables))
- sql_print_error("Cannot open mysql.db");
- else
- {
- table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields,
- &mysql_db_table_last_check,ER_CANNOT_LOAD_FROM_TABLE);
- close_thread_tables(thd);
- }
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "user";
- tables.lock_type= TL_READ;
-
- if (simple_open_n_lock_tables(thd, &tables))
- sql_print_error("Cannot open mysql.db");
- else
- {
- if (tables.table->s->fields < 29 ||
- strncmp(tables.table->field[29]->field_name,
- STRING_WITH_LEN("Event_priv")))
- sql_print_error("mysql.user has no `Event_priv` column at position 29");
-
- close_thread_tables(thd);
- }
-
- thd->restore_backup_open_tables_state(&backup);
-}
-
-
-/*
- Inits the scheduler. Called on server start and every time the scheduler
- is started with switching the event_scheduler global variable to TRUE
-
- SYNOPSIS
- init_events()
-
- NOTES
- Inits the mutexes used by the scheduler. Done at server start.
-*/
-
-int
-init_events()
-{
- pthread_t th;
- DBUG_ENTER("init_events");
-
- DBUG_PRINT("info",("Starting events main thread"));
-
- evex_check_system_tables();
-
- evex_init_mutexes();
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- if (event_executor_running_global_var)
- {
-#ifndef DBUG_FAULTY_THR
- /* TODO Andrey: Change the error code returned! */
- if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
- DBUG_RETURN(ER_SLAVE_THREAD);
-#else
- event_executor_main(NULL);
-#endif
- }
-
- DBUG_RETURN(0);
-}
-
-
-/*
- Cleans up scheduler memory. Called on server shutdown.
-
- SYNOPSIS
- shutdown_events()
-
- NOTES
- Destroys the mutexes.
-*/
-
-void
-shutdown_events()
-{
- DBUG_ENTER("shutdown_events");
-
- if (evex_mutexes_initted)
- {
- evex_mutexes_initted= FALSE;
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- pthread_mutex_destroy(&LOCK_event_arrays);
- pthread_mutex_destroy(&LOCK_workers_count);
- pthread_mutex_destroy(&LOCK_evex_running);
- pthread_mutex_destroy(&LOCK_evex_main_thread);
- }
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Inits an scheduler thread handler, both the main and a worker
-
- SYNOPSIS
- init_event_thread()
- thd - the THD of the thread. Has to be allocated by the caller.
-
- NOTES
- 1. The host of the thead is my_localhost
- 2. thd->net is initted with NULL - no communication.
-
- Returns
- 0 - OK
- -1 - Error
-*/
-
-static int
-init_event_thread(THD* thd)
-{
- DBUG_ENTER("init_event_thread");
- thd->client_capabilities= 0;
- thd->security_ctx->master_access= 0;
- thd->security_ctx->db_access= 0;
- thd->security_ctx->host_or_ip= (char*)my_localhost;
- my_net_init(&thd->net, 0);
- thd->net.read_timeout = slave_net_timeout;
- thd->slave_thread= 0;
- thd->options|= OPTION_AUTO_IS_NULL;
- thd->client_capabilities= CLIENT_LOCAL_FILES;
- thd->real_id=pthread_self();
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->thread_id= thread_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- if (init_thr_lock() || thd->store_globals())
- {
- thd->cleanup();
- delete thd;
- DBUG_RETURN(-1);
- }
-
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
- thd->proc_info= "Initialized";
- thd->version= refresh_version;
- thd->set_time();
- DBUG_RETURN(0);
-}
-
-
-/*
- This function waits till the time next event in the queue should be
- executed.
-
- Returns
- WAIT_STATUS_READY There is an event to be executed right now
- WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped.
- WAIT_STATUS_NEW_TOP_EVENT New event has entered the queue and scheduled
- on top. Restart ticking.
- WAIT_STATUS_STOP_EXECUTOR The thread was killed or SET global event_scheduler=0;
-*/
-
-static int
-executor_wait_till_next_event_exec(THD *thd)
-{
- Event_timed *et;
- TIME time_now;
- int t2sleep;
-
- DBUG_ENTER("executor_wait_till_next_event_exec");
- /*
- now let's see how much time to sleep, we know there is at least 1
- element in the queue.
- */
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_RETURN(WAIT_STATUS_EMPTY_QUEUE);
- }
- et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
- DBUG_ASSERT(et);
- if (et->status == MYSQL_EVENT_DISABLED)
- {
- DBUG_PRINT("evex main thread",("Now it is disabled-exec no more"));
- if (et->dropped)
- et->drop(thd);
- delete et;
- evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- sql_print_information("Event found disabled, dropping.");
- DBUG_RETURN(1);
- }
-
- DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
- /* set the internal clock of thd */
- thd->end_time();
- my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
- t2sleep= evex_time_diff(&et->execute_at, &time_now);
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
- t2sleep*=20;
- DBUG_PRINT("evex main thread",("unlocked LOCK_event_arrays"));
- if (t2sleep > 0)
- {
- ulonglong modified= et->modified;
- /*
- We sleep t2sleep seconds but we check every second whether this thread
- has been killed, or there is a new candidate
- */
- while (t2sleep-- && !thd->killed && event_executor_running_global_var &&
- evex_queue_num_elements(EVEX_EQ_NAME) &&
- (evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) == et &&
- evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified ==
- modified))
- {
- DBUG_PRINT("evex main thread",("will sleep a bit more."));
- my_sleep(50000);
- }
- DBUG_PRINT("info",("saved_modified=%llu current=%llu", modified,
- evex_queue_num_elements(EVEX_EQ_NAME)?
- evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified:
- (ulonglong)~0));
- }
-
- int ret= WAIT_STATUS_READY;
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- ret= WAIT_STATUS_EMPTY_QUEUE;
- else if (evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) != et)
- ret= WAIT_STATUS_NEW_TOP_EVENT;
- if (thd->killed && event_executor_running_global_var)
- ret= WAIT_STATUS_STOP_EXECUTOR;
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- The main scheduler thread. Inits the priority queue on start and
- destroys it on thread shutdown. Forks child threads for every event
- execution. Sleeps between thread forking and does not do a busy wait.
-
- SYNOPSIS
- event_executor_main()
- arg unused
-
- NOTES
- 1. The host of the thead is my_localhost
- 2. thd->net is initted with NULL - no communication.
-
-*/
-
-pthread_handler_t
-event_executor_main(void *arg)
-{
- THD *thd; /* needs to be first for thread_stack */
- uint i=0, j=0;
- my_ulonglong cnt= 0;
-
- DBUG_ENTER("event_executor_main");
- DBUG_PRINT("event_executor_main", ("EVEX thread started"));
-
- pthread_mutex_lock(&LOCK_evex_main_thread);
- if (!scheduler_main_thread_running)
- scheduler_main_thread_running= true;
- else
- {
- DBUG_PRINT("event_executor_main", ("already running. thd_id=%d",
- evex_main_thread_id));
- pthread_mutex_unlock(&LOCK_evex_main_thread);
- my_thread_end();
- pthread_exit(0);
- DBUG_RETURN(0); // Can't return anything here
- }
- pthread_mutex_unlock(&LOCK_evex_main_thread);
-
- /* init memory root */
- init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
-
- /* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
- my_thread_init();
-
- if (sizeof(my_time_t) != sizeof(time_t))
- {
- sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
- "The scheduler will not work correctly. Stopping.");
- DBUG_ASSERT(0);
- goto err_no_thd;
- }
-
- /* note that contructor of THD uses DBUG_ ! */
- if (!(thd = new THD))
- {
- sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
- goto err_no_thd;
- }
- thd->thread_stack = (char*)&thd; // remember where our stack is
-
- pthread_detach_this_thread();
-
- if (init_event_thread(thd))
- goto finish;
-
- /*
- make this thread visible it has no vio -> show processlist won't see it
- unless it's marked as system thread
- */
- thd->system_thread= 1;
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- threads.append(thd);
- thread_count++;
- thread_running++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- DBUG_PRINT("EVEX main thread", ("Initing events_queue"));
-
- /*
- eventually manifest that we are running, not to crashe because of
- usage of non-initialized memory structures.
- */
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- evex_queue_init(&EVEX_EQ_NAME);
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- evex_is_running= true;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- thd->security_ctx->user= my_strdup("event_scheduler", MYF(0));
-
- if (evex_load_events_from_db(thd))
- goto finish;
-
- evex_main_thread_id= thd->thread_id;
-
- sql_print_information("SCHEDULER: Main thread started");
- while (!thd->killed)
- {
- TIME time_now;
- Event_timed *et;
-
- cnt++;
- DBUG_PRINT("info", ("EVEX External Loop %d thd->k", cnt));
-
- thd->proc_info = "Sleeping";
- if (!event_executor_running_global_var)
- {
- sql_print_information("SCHEDULER: Asked to stop.");
- break;
- }
-
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- my_sleep(100000);// sleep 0.1s
- continue;
- }
-
-restart_ticking:
- switch (executor_wait_till_next_event_exec(thd)) {
- case WAIT_STATUS_READY: // time to execute the event on top
- DBUG_PRINT("evex main thread",("time to execute an event"));
- break;
- case WAIT_STATUS_EMPTY_QUEUE: // no more events
- DBUG_PRINT("evex main thread",("no more events"));
- continue;
- break;
- case WAIT_STATUS_NEW_TOP_EVENT: // new event on top in the queue
- DBUG_PRINT("evex main thread",("restart ticking"));
- goto restart_ticking;
- case WAIT_STATUS_STOP_EXECUTOR:
- sql_print_information("SCHEDULER: Asked to stop.");
- goto finish;
- break;
- default:
- DBUG_ASSERT(0);
- }
-
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- thd->end_time();
- my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
-
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_PRINT("evex main thread",("empty queue"));
- continue;
- }
- et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
- DBUG_PRINT("evex main thread",("got event from the queue"));
-
- if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1)
- {
- DBUG_PRINT("evex main thread",("still not the time for execution"));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- continue;
- }
-
- DBUG_PRINT("evex main thread",("it's right time"));
- if (et->status == MYSQL_EVENT_ENABLED)
- {
- int fork_ret_code;
-
- DBUG_PRINT("evex main thread", ("[%10s] this exec at [%llu]", et->name.str,
- TIME_to_ulonglong_datetime(&et->execute_at)));
- et->mark_last_executed(thd);
- if (et->compute_next_execution_time())
- {
- sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
- "Disabling after execution.",
- et->dbname.str, et->name.str);
- et->status= MYSQL_EVENT_DISABLED;
- }
- DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
- TIME_to_ulonglong_datetime(&et->execute_at)));
-
- et->update_fields(thd);
-#ifndef DBUG_FAULTY_THR
- thread_safe_increment(workers_count, &LOCK_workers_count);
- switch ((fork_ret_code= et->spawn_now(event_executor_worker))) {
- case EVENT_EXEC_CANT_FORK:
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- sql_print_error("SCHEDULER: Problem while trying to create a thread");
- UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_event_arrays, finish);
- case EVENT_EXEC_ALREADY_EXEC:
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- sql_print_information("SCHEDULER: %s.%s in execution. Skip this time.",
- et->dbname.str, et->name.str);
- break;
- default:
- DBUG_ASSERT(!fork_ret_code);
- if (fork_ret_code)
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- break;
- }
-#else
- event_executor_worker((void *) et);
-#endif
- /*
- 1. For one-time event : year is > 0 and expression is 0
- 2. For recurring, expression is != -=> check execute_at_null in this case
- */
- if ((et->execute_at.year && !et->expression) || et->execute_at_null)
- et->flags |= EVENT_EXEC_NO_MORE;
-
- if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED)
- evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
- else
- evex_queue_first_updated(&EVEX_EQ_NAME);
- }
- DBUG_PRINT("evex main thread",("unlocking"));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- }/* while */
-finish:
-
- /* First manifest that this thread does not work and then destroy */
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- evex_main_thread_id= 0;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-
- /*
- TODO: A better will be with a conditional variable
- */
- /*
- Read workers_count without lock, no need for locking.
- In the worst case we have to wait 1sec more.
- */
- sql_print_information("SCHEDULER: Stopping. Waiting for worker threads to finish.");
- while (1)
- {
- VOID(pthread_mutex_lock(&LOCK_workers_count));
- if (!workers_count)
- {
- VOID(pthread_mutex_unlock(&LOCK_workers_count));
- break;
- }
- VOID(pthread_mutex_unlock(&LOCK_workers_count));
- my_sleep(1000000);// 1s
- }
-
- /*
- First we free all objects ...
- Lock because a DROP DATABASE could be running in parallel and it locks on these
- */
- sql_print_information("SCHEDULER: Emptying the queue.");
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- et->free_sp();
- delete et;
- }
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- /* ... then we can thrash the whole queue at once */
- evex_queue_destroy(&EVEX_EQ_NAME);
-
- thd->proc_info = "Clearing";
- DBUG_ASSERT(thd->net.buff != 0);
- net_end(&thd->net); // destructor will not free it, because we are weird
- THD_CHECK_SENTRY(thd);
-
- pthread_mutex_lock(&LOCK_thread_count);
- thread_count--;
- thread_running--;
-#ifndef DBUG_FAULTY_THR
- THD_CHECK_SENTRY(thd);
- delete thd;
-#endif
- pthread_mutex_unlock(&LOCK_thread_count);
-
-
-err_no_thd:
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- event_executor_running_global_var= false;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- free_root(&evex_mem_root, MYF(0));
- sql_print_information("SCHEDULER: Stopped.");
-
-#ifndef DBUG_FAULTY_THR
- pthread_mutex_lock(&LOCK_evex_main_thread);
- scheduler_main_thread_running= false;
- pthread_mutex_unlock(&LOCK_evex_main_thread);
-
- my_thread_end();
- pthread_exit(0);
-#endif
- DBUG_RETURN(0); // Can't return anything here
-}
-
-
-/*
- Function that executes an event in a child thread. Setups the
- environment for the event execution and cleans after that.
-
- SYNOPSIS
- event_executor_worker()
- arg The Event_timed object to be processed
-*/
-
-pthread_handler_t
-event_executor_worker(void *event_void)
-{
- THD *thd; /* needs to be first for thread_stack */
- Event_timed *event = (Event_timed *) event_void;
- MEM_ROOT worker_mem_root;
-
- DBUG_ENTER("event_executor_worker");
-
- init_alloc_root(&worker_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
-
-#ifndef DBUG_FAULTY_THR
- my_thread_init();
-
- if (!(thd = new THD)) /* note that contructor of THD uses DBUG_ ! */
- {
- sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
- goto err_no_thd;
- }
- thd->thread_stack = (char*)&thd; // remember where our stack is
- thd->mem_root= &worker_mem_root;
-
- pthread_detach_this_thread();
-
- if (init_event_thread(thd))
- goto err;
-
- thd->init_for_queries();
-
- /* make this thread visible it has no vio -> show processlist needs this flag */
- thd->system_thread= 1;
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- threads.append(thd);
- thread_count++;
- thread_running++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-#else
- thd= current_thd;
-#endif
-
- thd->enable_slow_log= TRUE;
- {
- int ret;
- sql_print_information("SCHEDULER: Executing event %s.%s of %s [EXPR:%d]",
- event->dbname.str, event->name.str,
- event->definer.str, (int) event->expression);
-
- ret= event->execute(thd, &worker_mem_root);
-
- evex_print_warnings(thd, event);
- sql_print_information("SCHEDULER: Executed event %s.%s of %s [EXPR:%d]. "
- "RetCode=%d", event->dbname.str, event->name.str,
- event->definer.str, (int) event->expression, ret);
- if (ret == EVEX_COMPILE_ERROR)
- sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of",
- event->dbname.str, event->name.str,
- event->definer.str);
- else if (ret == EVEX_MICROSECOND_UNSUP)
- sql_print_information("SCHEDULER: MICROSECOND is not supported");
- }
- event->spawn_thread_finish(thd);
-
-
-err:
- VOID(pthread_mutex_lock(&LOCK_thread_count));
-#ifndef DBUG_FAULTY_THR
- thread_count--;
- thread_running--;
- /*
- Some extra safety, which should not been needed (normally, event deletion
- should already have done these assignments (each event which sets these
- variables is supposed to set them to 0 before terminating)).
- */
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- thd->proc_info = "Clearing";
- DBUG_ASSERT(thd->net.buff != 0);
- net_end(&thd->net); // destructor will not free it, because we are weird
- THD_CHECK_SENTRY(thd);
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- THD_CHECK_SENTRY(thd);
- delete thd;
-#endif
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
-err_no_thd:
-
- free_root(&worker_mem_root, MYF(0));
- thread_safe_decrement(workers_count, &LOCK_workers_count);
-
-#ifndef DBUG_FAULTY_THR
- my_thread_end();
- pthread_exit(0);
-#endif
- DBUG_RETURN(0); // Can't return anything here
-}
-
-
-/*
- Loads all ENABLED events from mysql.event into the prioritized
- queue. Called during scheduler main thread initialization. Compiles
- the events. Creates Event_timed instances for every ENABLED event
- from mysql.event.
-
- SYNOPSIS
- evex_load_events_from_db()
- thd - Thread context. Used for memory allocation in some cases.
-
- RETURNS
- 0 OK
- !0 Error
-
- NOTES
- Reports the error to the console
-*/
-
-static int
-evex_load_events_from_db(THD *thd)
-{
- TABLE *table;
- READ_RECORD read_record_info;
- int ret= -1;
- uint count= 0;
-
- DBUG_ENTER("evex_load_events_from_db");
-
- if ((ret= evex_open_event_table(thd, TL_READ, &table)))
- {
- sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- init_read_record(&read_record_info, thd, table ,NULL,1,0);
- while (!(read_record_info.read_record(&read_record_info)))
- {
- Event_timed *et;
- if (!(et= new Event_timed))
- {
- DBUG_PRINT("evex_load_events_from_db", ("Out of memory"));
- ret= -1;
- goto end;
- }
- DBUG_PRINT("evex_load_events_from_db", ("Loading event from row."));
-
- if ((ret= et->load_from_row(&evex_mem_root, table)))
- {
- sql_print_error("SCHEDULER: Error while loading from mysql.event. "
- "Table probably corrupted");
- goto end;
- }
- if (et->status != MYSQL_EVENT_ENABLED)
- {
- DBUG_PRINT("evex_load_events_from_db",("%s is disabled",et->name.str));
- delete et;
- continue;
- }
-
- DBUG_PRINT("evex_load_events_from_db",
- ("Event %s loaded from row. Time to compile", et->name.str));
-
- switch (ret= et->compile(thd, &evex_mem_root)) {
- case EVEX_MICROSECOND_UNSUP:
- sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
- "supported but found in mysql.event");
- goto end;
- case EVEX_COMPILE_ERROR:
- sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
- et->dbname.str, et->name.str);
- goto end;
- default:
- break;
- }
-
- /* let's find when to be executed */
- if (et->compute_next_execution_time())
- {
- sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
- " Skipping", et->dbname.str, et->name.str);
- continue;
- }
-
- DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
-
- evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et);
- DBUG_PRINT("evex_load_events_from_db", ("%p %*s",
- et, et->name.length,et->name.str));
- count++;
- }
-
- ret= 0;
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- end_read_record(&read_record_info);
-
- /* Force close to free memory */
- thd->version--;
-
- close_thread_tables(thd);
- if (!ret)
- sql_print_information("SCHEDULER: Loaded %d event%s", count, (count == 1)?"":"s");
- DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- The update method of the global variable event_scheduler.
- If event_scheduler is switched from 0 to 1 then the scheduler main
- thread is started.
-
- SYNOPSIS
- event_executor_worker()
- thd - Thread context (unused)
- car - the new value
-
- Returns
- 0 OK (always)
-*/
-
-bool
-sys_var_event_executor::update(THD *thd, set_var *var)
-{
- /* here start the thread if not running. */
- DBUG_ENTER("sys_var_event_executor::update");
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- *value= var->save_result.ulong_value;
-
- DBUG_PRINT("new_value", ("%d", *value));
- if ((my_bool) *value && !evex_is_running)
- {
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
- init_events();
- } else
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- DBUG_RETURN(0);
-}
-
-
-extern LEX_STRING warning_level_names[];
-
-typedef void (*sql_print_xxx_func)(const char *format, ...);
-static sql_print_xxx_func sql_print_xxx_handlers[3] =
-{
- sql_print_information,
- sql_print_warning,
- sql_print_error
-};
-
-
-/*
- Prints the stack of infos, warnings, errors from thd to
- the console so it can be fetched by the logs-into-tables and
- checked later.
-
- Synopsis
- evex_print_warnings
- thd - thread used during the execution of the event
- et - the event itself
-
- Returns
- 0 - OK (always)
-
-*/
-
-bool
-evex_print_warnings(THD *thd, Event_timed *et)
-{
- MYSQL_ERROR *err;
- DBUG_ENTER("evex_show_warnings");
- char msg_buf[1024];
- char prefix_buf[512];
- String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
- prefix.length(0);
-
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
- while ((err= it++))
- {
- String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
- /* set it to 0 or we start adding at the end. That's the trick ;) */
- err_msg.length(0);
- if (!prefix.length())
- {
- prefix.append("SCHEDULER: [");
-
- append_identifier(thd,&prefix,et->definer_user.str,et->definer_user.length);
- prefix.append('@');
- append_identifier(thd,&prefix,et->definer_host.str,et->definer_host.length);
- prefix.append("][", 2);
- append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
- prefix.append('.');
- append_identifier(thd,&prefix, et->name.str, et->name.length);
- prefix.append("] ", 2);
- }
-
- err_msg.append(prefix);
- err_msg.append(err->msg, strlen(err->msg), system_charset_info);
- err_msg.append("]");
- DBUG_ASSERT(err->level < 3);
- (sql_print_xxx_handlers[err->level])("%*s", err_msg.length(), err_msg.c_ptr());
- }
-
-
- DBUG_RETURN(FALSE);
-}
diff --git a/sql/event_priv.h b/sql/event_priv.h
index 6b23136847e..43ef30a659f 100644
--- a/sql/event_priv.h
+++ b/sql/event_priv.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2004-2005 MySQL AB
+#ifndef _EVENT_PRIV_H_
+#define _EVENT_PRIV_H_
+/* Copyright (C) 2004-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
@@ -14,8 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef _EVENT_PRIV_H_
-#define _EVENT_PRIV_H_
#include "mysql_priv.h"
@@ -23,11 +23,6 @@
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
-#define EVEX_USE_QUEUE
-
-#define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
- { VOID(pthread_mutex_unlock(&__mutex)); goto __label; }
-
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
@@ -38,45 +33,54 @@ my_time_compare(TIME *a, TIME *b);
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
- const LEX_STRING user_name,
TABLE *table);
int
event_timed_compare_q(void *vptr, byte* a, byte *b);
-int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
- uint *rows_affected);
-
+int
+db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+ uint *rows_affected);
+int
+db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
+ MEM_ROOT *root);
-#define EXEC_QUEUE_QUEUE_NAME executing_queue
-#define EXEC_QUEUE_DARR_NAME evex_executing_queue
+int
+db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
+ uint *rows_affected);
+int
+db_drop_events_from_table(THD *thd, LEX_STRING *db);
-#define EVEX_QUEUE_TYPE QUEUE
-#define EVEX_PTOQEL byte *
+int
+sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
-#define EVEX_EQ_NAME executing_queue
-#define evex_queue_first_element(queue, __cast) ((__cast)queue_top(queue))
-#define evex_queue_element(queue, idx, __cast) ((__cast)queue_element(queue, idx))
-#define evex_queue_delete_element(queue, idx) queue_remove(queue, idx)
-#define evex_queue_destroy(queue) delete_queue(queue)
-#define evex_queue_first_updated(queue) queue_replaced(queue)
-#define evex_queue_insert(queue, element) queue_insert_safe(queue, element);
+/* Compares only the name part of the identifier */
+bool
+event_timed_name_equal(Event_timed *et, LEX_STRING *name);
+/* Compares only the schema part of the identifier */
+bool
+event_timed_db_equal(Event_timed *et, LEX_STRING *db);
+/*
+ Compares only the definer part of the identifier. Use during DROP USER
+ to drop user's events. (Still not implemented)
+*/
+bool
+event_timed_definer_equal(Event_timed *et, LEX_STRING *definer);
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue);
+/* Compares the whole identifier*/
+bool
+event_timed_identifier_equal(Event_timed *a, Event_timed *b);
-#define evex_queue_num_elements(queue) queue.elements
+bool
+change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
+ LEX_STRING db, Security_context *s_ctx,
+ Security_context **backup);
-extern bool evex_is_running;
-extern MEM_ROOT evex_mem_root;
-extern pthread_mutex_t LOCK_event_arrays,
- LOCK_workers_count,
- LOCK_evex_running;
-extern ulonglong evex_main_thread_id;
-extern QUEUE EVEX_EQ_NAME;
+void
+restore_security_context(THD *thd, Security_context *backup);
#endif /* _EVENT_PRIV_H_ */
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
new file mode 100644
index 00000000000..db855e9135b
--- /dev/null
+++ b/sql/event_scheduler.cc
@@ -0,0 +1,2432 @@
+/* Copyright (C) 2004-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 */
+
+#include "event_priv.h"
+#include "event.h"
+#include "event_scheduler.h"
+#include "sp_head.h"
+
+/*
+ ToDo:
+ 1. Talk to Alik to get a check for configure.in for my_time_t and time_t
+ 2. Look at guardian.h|cc to see its life cycle, has similarities.
+*/
+
+
+/*
+ The scheduler is implemented as class Event_scheduler. Only one instance is
+ kept during the runtime of the server, by implementing the Singleton DP.
+ Object instance is always there because the memory is allocated statically
+ and initialized when the OS loader loads mysqld. This initialization is
+ bare. Extended initialization is done during the call to
+ Event_scheduler::init() in Events::init(). The reason for that late initialization
+ is that some subsystems needed to boot the Scheduler are not available at
+ earlier stages of the mysqld boot procedure. Events::init() is called in
+ mysqld.cc . If the mysqld is started with --event-scheduler=0 then
+ no initialization takes place and the scheduler is unavailable during this
+ server run. The server should be started with --event-scheduler=1 to have
+ the scheduler initialized and able to execute jobs. This starting alwa
+ s implies that the jobs execution will start immediately. If the server
+ is started with --event-scheduler=2 then the scheduler is started in suspended
+ state. Default state, if --event-scheduler is not specified is 2.
+
+ The scheduler only manages execution of the events. Their creation,
+ alteration and deletion is delegated to other routines found in event.cc .
+ These routines interact with the scheduler :
+ - CREATE EVENT -> Event_scheduler::add_event()
+ - ALTER EVENT -> Event_scheduler::replace_event()
+ - DROP EVENT -> Event_scheduler::drop_event()
+
+ There is one mutex in the single Event_scheduler object which controls
+ the simultaneous access to the objects invariants. Using one lock makes
+ it easy to follow the workflow. This mutex is LOCK_scheduler_data. It is
+ initialized in Event_scheduler::init(). Which in turn is called by the
+ Facade class Events in event.cc, coming from init_thread_environment() from
+ mysqld.cc -> no concurrency at this point. It's destroyed in
+ Events::destroy_mutexes() called from clean_up_mutexes() in mysqld.cc .
+
+ The full initialization is done in Event_scheduler::init() called from
+ Events::init(). It's done before any requests coming in, so this is a
+ guarantee for not having concurrency.
+
+ The scheduler is started with Event_scheduler::start() and stopped with
+ Event_scheduler::stop(). When the scheduler starts it loads all events
+ from mysql.event table. Unfortunately, there is a race condition between
+ the event disk management functions and the scheduler ones
+ (add/replace/drop_event & load_events_from_db()), because the operations
+ do not happen under one global lock but the disk operations are guarded
+ by the MYISAM lock on mysql.event. In the same time, the queue operations
+ are guarded by LOCK_scheduler_data. If the scheduler is start()-ed during
+ server startup and stopped()-ed during server shutdown (in Events::shutdown()
+ called by kill_server() in mysqld.cc) these races does not exist.
+
+ Since the user may want to temporarily inhibit execution of events the
+ scheduler can be suspended and then it can be forced to resume its
+ operations. The API call to perform these is
+ Event_scheduler::suspend_or_resume(enum enum_suspend_or_resume) .
+ When the scheduler is suspended the main scheduler thread, which ATM
+ happens to have thread_id 1, locks on a condition COND_suspend_or_resume.
+ When this is signal is sent for the reverse operation the main scheduler
+ loops continues to roll and execute events.
+
+ When the scheduler is suspended all add/replace/drop_event() operations
+ work as expected and the modify the queue but no events execution takes
+ place.
+
+ In contrast to the previous scheduler implementation, found in
+ event_executor.cc, the start, shutdown, suspend and resume are synchronous
+ operations. As a whole all operations are synchronized and no busy waits
+ are used except in stop_all_running_events(), which waits until all
+ running event worker threads have finished. It would have been nice to
+ use a conditional on which this method will wait and the last thread to
+ finish would signal it but this implies subclassing THD.
+
+ The scheduler does not keep a counter of how many event worker threads are
+ running, at any specific moment, because this will copy functionality
+ already existing in the server. Namely, all THDs are registered in the
+ global `threads` array. THD has member variable system_thread which
+ identifies the type of thread. Connection threads being NON_SYSTEM_THREAD,
+ all other have their enum value. Important for the scheduler are
+ SYSTEM_THREAD_EVENT_SCHEDULER and SYSTEM_THREAD_EVENT_WORKER.
+
+ Class THD subclasses class ilink, which is the linked list of all threads.
+ When a THD instance is destroyed it's being removed from threads, thus
+ no manual intervention is needed. On the contrary registering is manual
+ with threads.append() . Traversing the threads array every time a subclass
+ of THD, for instance if we would have had THD_scheduler_worker to see
+ how many events we have and whether the scheduler is shutting down will
+ take much time and lead to a deadlock. stop_all_running_events() is called
+ under LOCK_scheduler_data. If the THD_scheduler_worker was aware of
+ the single Event_scheduler instance it will try to check
+ Event_scheduler::state but for this it would need to acquire
+ LOCK_scheduler_data => deadlock. Thus stop_all_running_events() uses a
+ busy wait.
+
+ DROP DATABASE DDL should drop all events defined in a specific schema.
+ DROP USER also should drop all events who has as definer the user being
+ dropped (this one is not addressed at the moment but a hook exists). For
+ this specific needs Event_scheduler::drop_matching_events() is
+ implemented. Which expects a callback to be applied on every object in
+ the queue. Thus events that match specific schema or user, will be
+ removed from the queue. The exposed interface is :
+ - Event_scheduler::drop_schema_events()
+ - Event_scheduler::drop_user_events()
+
+ This bulk dropping happens under LOCK_scheduler_data, thus no two or
+ more threads can execute it in parallel. However, DROP DATABASE is also
+ synchronized, currently, in the server thus this does not impact the
+ overall performance. In addition, DROP DATABASE is not that often
+ executed DDL.
+
+ Though the interface to the scheduler is only through the public methods
+ of class Event_scheduler, there are currently few functions which are
+ used during its operations. Namely :
+ - static evex_print_warnings()
+ After every event execution all errors/warnings are dumped, so the user
+ can see in case of a problem what the problem was.
+
+ - static init_event_thread()
+ This function is both used by event_scheduler_thread() and
+ event_worker_thread(). It initializes the THD structure. The
+ initialization looks pretty similar to the one in slave.cc done for the
+ replication threads. However, though the similarities it cannot be
+ factored out to have one routine.
+
+ - static event_scheduler_thread()
+ Because our way to register functions to be used by the threading library
+ does not allow usage of static methods this function is used to start the
+ scheduler in it. It does THD initialization and then calls
+ Event_scheduler::run().
+
+ - static event_worker_thread()
+ With already stated the reason for not being able to use methods, this
+ function executes the worker threads.
+
+ The execution of events is, to some extent, synchronized to inhibit race
+ conditions when Event_timed::thread_id is being updated with the thread_id of
+ the THD in which the event is being executed. The thread_id is in the
+ Event_timed object because we need to be able to kill quickly a specific
+ event during ALTER/DROP EVENT without traversing the global `threads` array.
+ However, this makes the scheduler's code more complicated. The event worker
+ thread is started by Event_timed::spawn_now(), which in turn calls
+ pthread_create(). The thread_id which will be associated in init_event_thread
+ is not known in advance thus the registering takes place in
+ event_worker_thread(). This registering has to be synchronized under
+ LOCK_scheduler_data, so no kill_event() on a object in
+ replace_event/drop_event/drop_matching_events() could take place.
+
+ This synchronization is done through class Worker_thread_param that is
+ local to this file. Event_scheduler::execute_top() is called under
+ LOCK_scheduler_data. This method :
+ 1. Creates an instance of Worker_thread_param on the stack
+ 2. Locks Worker_thread_param::LOCK_started
+ 3. Calls Event_timed::spawn_now() which in turn creates a new thread.
+ 4. Locks on Worker_thread_param::COND_started_or_stopped and waits till the
+ worker thread send signal. The code is spurious wake-up safe because
+ Worker_thread_param::started is checked.
+ 5. The worker thread initializes its THD, then sets Event_timed::thread_id,
+ sets Worker_thread_param::started to TRUE and sends back
+ Worker_thread_param::COND_started. From this moment on, the event
+ is being executed and could be killed by using Event_timed::thread_id.
+ When Event_timed::spawn_thread_finish() is called in the worker thread,
+ it sets thread_id to 0. From this moment on, the worker thread should not
+ touch the Event_timed instance.
+
+
+ The life-cycle of the server is a FSA.
+ enum enum_state Event_scheduler::state keeps the state of the scheduler.
+
+ The states are:
+
+ |---UNINITIALIZED
+ |
+ | |------------------> IN_SHUTDOWN
+ --> INITIALIZED -> COMMENCING ---> RUNNING ----------|
+ ^ ^ | | ^ |
+ | |- CANTSTART <--| | |- SUSPENDED <-|
+ |______________________________|
+
+ - UNINITIALIZED :The object is created and only the mutex is initialized
+ - INITIALIZED :All member variables are initialized
+ - COMMENCING :The scheduler is starting, no other attempt to start
+ should succeed before the state is back to INITIALIZED.
+ - CANTSTART :Set by the ::run() method in case it can't start for some
+ reason. In this case the connection thread that tries to
+ start the scheduler sees that some error has occurred and
+ returns an error to the user. Finally, the connection
+ thread sets the state to INITIALIZED, so further attempts
+ to start the scheduler could be made.
+ - RUNNING :The scheduler is running. New events could be added,
+ dropped, altered. The scheduler could be stopped.
+ - SUSPENDED :Like RUNNING but execution of events does not take place.
+ Operations on the memory queue are possible.
+ - IN_SHUTDOWN :The scheduler is shutting down, due to request by setting
+ the global event_scheduler to 0/FALSE, or because of a
+ KILL command sent by a user to the master thread.
+
+ In every method the macros LOCK_SCHEDULER_DATA() and UNLOCK_SCHEDULER_DATA()
+ are used for (un)locking purposes. They are used to save the programmer
+ from typing everytime
+ lock_data(__FUNCTION__, __LINE__);
+ All locking goes through Event_scheduler::lock_data() and ::unlock_data().
+ These two functions then record in variables where for last time
+ LOCK_scheduler_data was locked and unlocked (two different variables). In
+ multithreaded environment, in some cases they make no sense but are useful for
+ inspecting deadlocks without having the server debug log turned on and the
+ server is still running.
+
+ The same strategy is used for conditional variables.
+ Event_scheduler::cond_wait() is invoked from all places with parameter
+ an enum enum_cond_vars. In this manner, it's possible to inspect the last
+ on which condition the last call to cond_wait() was waiting. If the server
+ was started with debug trace switched on, the trace file also holds information
+ about conditional variables used.
+*/
+
+#ifdef __GNUC__
+#if __GNUC__ >= 2
+#define SCHED_FUNC __FUNCTION__
+#endif
+#else
+#define SCHED_FUNC "<unknown>"
+#endif
+
+#define LOCK_SCHEDULER_DATA() lock_data(SCHED_FUNC, __LINE__)
+#define UNLOCK_SCHEDULER_DATA() unlock_data(SCHED_FUNC, __LINE__)
+
+
+#ifndef DBUG_OFF
+static
+LEX_STRING states_names[] =
+{
+ {(char*) STRING_WITH_LEN("UNINITIALIZED")},
+ {(char*) STRING_WITH_LEN("INITIALIZED")},
+ {(char*) STRING_WITH_LEN("COMMENCING")},
+ {(char*) STRING_WITH_LEN("CANTSTART")},
+ {(char*) STRING_WITH_LEN("RUNNING")},
+ {(char*) STRING_WITH_LEN("SUSPENDED")},
+ {(char*) STRING_WITH_LEN("IN_SHUTDOWN")}
+};
+#endif
+
+
+Event_scheduler
+Event_scheduler::singleton;
+
+
+const char * const
+Event_scheduler::cond_vars_names[Event_scheduler::COND_LAST] =
+{
+ "new work",
+ "started or stopped",
+ "suspend or resume"
+};
+
+
+class Worker_thread_param
+{
+public:
+ Event_timed *et;
+ pthread_mutex_t LOCK_started;
+ pthread_cond_t COND_started;
+ bool started;
+
+ Worker_thread_param(Event_timed *etn):et(etn), started(FALSE)
+ {
+ pthread_mutex_init(&LOCK_started, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_started, NULL);
+ }
+
+ ~Worker_thread_param()
+ {
+ pthread_mutex_destroy(&LOCK_started);
+ pthread_cond_destroy(&COND_started);
+ }
+};
+
+
+/*
+ Prints the stack of infos, warnings, errors from thd to
+ the console so it can be fetched by the logs-into-tables and
+ checked later.
+
+ SYNOPSIS
+ evex_print_warnings
+ thd - thread used during the execution of the event
+ et - the event itself
+*/
+
+static void
+evex_print_warnings(THD *thd, Event_timed *et)
+{
+ MYSQL_ERROR *err;
+ DBUG_ENTER("evex_print_warnings");
+ if (!thd->warn_list.elements)
+ DBUG_VOID_RETURN;
+
+ char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
+ char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE];
+ String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
+ prefix.length(0);
+ prefix.append("SCHEDULER: [");
+
+ append_identifier(thd, &prefix, et->definer_user.str, et->definer_user.length);
+ prefix.append('@');
+ append_identifier(thd, &prefix, et->definer_host.str, et->definer_host.length);
+ prefix.append("][", 2);
+ append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
+ prefix.append('.');
+ append_identifier(thd,&prefix, et->name.str, et->name.length);
+ prefix.append("] ", 2);
+
+ List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ while ((err= it++))
+ {
+ String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
+ /* set it to 0 or we start adding at the end. That's the trick ;) */
+ err_msg.length(0);
+ err_msg.append(prefix);
+ err_msg.append(err->msg, strlen(err->msg), system_charset_info);
+ err_msg.append("]");
+ DBUG_ASSERT(err->level < 3);
+ (sql_print_message_handlers[err->level])("%*s", err_msg.length(),
+ err_msg.c_ptr());
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Inits an scheduler thread handler, both the main and a worker
+
+ SYNOPSIS
+ init_event_thread()
+ thd - the THD of the thread. Has to be allocated by the caller.
+
+ NOTES
+ 1. The host of the thead is my_localhost
+ 2. thd->net is initted with NULL - no communication.
+
+ RETURN VALUE
+ 0 OK
+ -1 Error
+*/
+
+static int
+init_event_thread(THD** t, enum enum_thread_type thread_type)
+{
+ THD *thd= *t;
+ thd->thread_stack= (char*)t; // remember where our stack is
+ DBUG_ENTER("init_event_thread");
+ thd->client_capabilities= 0;
+ thd->security_ctx->master_access= 0;
+ thd->security_ctx->db_access= 0;
+ thd->security_ctx->host_or_ip= (char*)my_localhost;
+ my_net_init(&thd->net, 0);
+ thd->net.read_timeout= slave_net_timeout;
+ thd->slave_thread= 0;
+ thd->options|= OPTION_AUTO_IS_NULL;
+ thd->client_capabilities|= CLIENT_MULTI_RESULTS;
+ thd->real_id=pthread_self();
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->thread_id= thread_id++;
+ threads.append(thd);
+ thread_count++;
+ thread_running++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ if (init_thr_lock() || thd->store_globals())
+ {
+ thd->cleanup();
+ DBUG_RETURN(-1);
+ }
+
+#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+ /*
+ Guarantees that we will see the thread in SHOW PROCESSLIST though its
+ vio is NULL.
+ */
+ thd->system_thread= thread_type;
+
+ thd->proc_info= "Initialized";
+ thd->version= refresh_version;
+ thd->set_time();
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Inits the main scheduler thread and then calls Event_scheduler::run()
+ of arg.
+
+ SYNOPSIS
+ event_scheduler_thread()
+ arg void* ptr to Event_scheduler
+
+ NOTES
+ 1. The host of the thead is my_localhost
+ 2. thd->net is initted with NULL - no communication.
+ 3. The reason to have a proxy function is that it's not possible to
+ use a method as function to be executed in a spawned thread:
+ - our pthread_hander_t macro uses extern "C"
+ - separating thread setup from the real execution loop is also to be
+ considered good.
+
+ RETURN VALUE
+ 0 OK
+*/
+
+pthread_handler_t
+event_scheduler_thread(void *arg)
+{
+ /* needs to be first for thread_stack */
+ THD *thd= NULL;
+ Event_scheduler *scheduler= (Event_scheduler *) arg;
+
+ DBUG_ENTER("event_scheduler_thread");
+
+ my_thread_init();
+ pthread_detach_this_thread();
+
+ /* note that constructor of THD uses DBUG_ ! */
+ if (!(thd= new THD) || init_event_thread(&thd, SYSTEM_THREAD_EVENT_SCHEDULER))
+ {
+ sql_print_error("SCHEDULER: Cannot init manager event thread.");
+ scheduler->report_error_during_start();
+ }
+ else
+ {
+ thd->security_ctx->set_user((char*)"event_scheduler");
+
+ sql_print_information("SCHEDULER: Manager thread booting");
+ if (Event_scheduler::check_system_tables(thd))
+ scheduler->report_error_during_start();
+ else
+ scheduler->run(thd);
+
+ /*
+ NOTE: Don't touch `scheduler` after this point because we have notified
+ the
+ thread which shuts us down that we have finished cleaning. In this
+ very moment a new scheduler thread could be started and a crash is
+ not welcome.
+ */
+ }
+
+ /*
+ If we cannot create THD then don't decrease because we haven't touched
+ thread_count and thread_running in init_event_thread() which was never
+ called. In init_event_thread() thread_count and thread_running are
+ always increased even in the case the method returns an error.
+ */
+ if (thd)
+ {
+ thd->proc_info= "Clearing";
+ DBUG_ASSERT(thd->net.buff != 0);
+ net_end(&thd->net);
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ thread_running--;
+ delete thd;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+ my_thread_end();
+ DBUG_RETURN(0); // Can't return anything here
+}
+
+
+/*
+ Function that executes an event in a child thread. Setups the
+ environment for the event execution and cleans after that.
+
+ SYNOPSIS
+ event_worker_thread()
+ arg The Event_timed object to be processed
+
+ RETURN VALUE
+ 0 OK
+*/
+
+pthread_handler_t
+event_worker_thread(void *arg)
+{
+ THD *thd; /* needs to be first for thread_stack */
+ Worker_thread_param *param= (Worker_thread_param *) arg;
+ Event_timed *event= param->et;
+ int ret;
+ bool startup_error= FALSE;
+ Security_context *save_ctx;
+ /* this one is local and not needed after exec */
+ Security_context security_ctx;
+
+ DBUG_ENTER("event_worker_thread");
+ DBUG_PRINT("enter", ("event=[%s.%s]", event->dbname.str, event->name.str));
+
+ my_thread_init();
+ pthread_detach_this_thread();
+
+ if (!(thd= new THD) || init_event_thread(&thd, SYSTEM_THREAD_EVENT_WORKER))
+ {
+ sql_print_error("SCHEDULER: Startup failure.");
+ startup_error= TRUE;
+ event->spawn_thread_finish(thd);
+ }
+ else
+ event->set_thread_id(thd->thread_id);
+
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access, thd->security_ctx->db_access));
+ /*
+ If we don't change it before we send the signal back, then an intermittent
+ DROP EVENT will take LOCK_scheduler_data and try to kill this thread, because
+ event->thread_id is already real. However, because thd->security_ctx->user
+ is not initialized then a crash occurs in kill_one_thread(). Thus, we have
+ to change the context before sending the signal. We are under
+ LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
+ */
+ change_security_context(thd, event->definer_user, event->definer_host,
+ event->dbname, &security_ctx, &save_ctx);
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access, thd->security_ctx->db_access));
+
+ /* Signal the scheduler thread that we have started successfully */
+ pthread_mutex_lock(&param->LOCK_started);
+ param->started= TRUE;
+ pthread_cond_signal(&param->COND_started);
+ pthread_mutex_unlock(&param->LOCK_started);
+
+ if (!startup_error)
+ {
+ thd->init_for_queries();
+ thd->enable_slow_log= TRUE;
+
+ event->set_thread_id(thd->thread_id);
+ sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu",
+ event->dbname.str, event->name.str,
+ event->definer.str, thd->thread_id);
+
+ ret= event->execute(thd, thd->mem_root);
+ evex_print_warnings(thd, event);
+ sql_print_information("SCHEDULER: [%s.%s of %s] executed. RetCode=%d",
+ event->dbname.str, event->name.str,
+ event->definer.str, ret);
+ if (ret == EVEX_COMPILE_ERROR)
+ sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
+ event->dbname.str, event->name.str,
+ event->definer.str);
+ else if (ret == EVEX_MICROSECOND_UNSUP)
+ sql_print_information("SCHEDULER: MICROSECOND is not supported");
+
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access, thd->security_ctx->db_access));
+
+ /* If true is returned, we are expected to free it */
+ if (event->spawn_thread_finish(thd))
+ {
+ DBUG_PRINT("info", ("Freeing object pointer"));
+ delete event;
+ }
+ }
+
+ if (thd)
+ {
+ thd->proc_info= "Clearing";
+ DBUG_ASSERT(thd->net.buff != 0);
+ /*
+ Free it here because net.vio is NULL for us => THD::~THD will check it
+ and won't call net_end(&net); See also replication code.
+ */
+ net_end(&thd->net);
+ DBUG_PRINT("info", ("Worker thread %lu exiting", thd->thread_id));
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thread_count--;
+ thread_running--;
+ delete thd;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ }
+
+ my_thread_end();
+ DBUG_RETURN(0); // Can't return anything here
+}
+
+
+/*
+ Constructor of class Event_scheduler.
+
+ SYNOPSIS
+ Event_scheduler::Event_scheduler()
+*/
+
+Event_scheduler::Event_scheduler()
+ :state(UNINITIALIZED), start_scheduler_suspended(FALSE),
+ thread_id(0), mutex_last_locked_at_line(0),
+ mutex_last_unlocked_at_line(0), mutex_last_locked_in_func(""),
+ mutex_last_unlocked_in_func(""), cond_waiting_on(COND_NONE),
+ mutex_scheduler_data_locked(FALSE)
+{
+}
+
+
+/*
+ Returns the singleton instance of the class.
+
+ SYNOPSIS
+ Event_scheduler::get_instance()
+
+ RETURN VALUE
+ address
+*/
+
+Event_scheduler*
+Event_scheduler::get_instance()
+{
+ DBUG_ENTER("Event_scheduler::get_instance");
+ DBUG_RETURN(&singleton);
+}
+
+
+/*
+ The implementation of full-fledged initialization.
+
+ SYNOPSIS
+ Event_scheduler::init()
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+*/
+
+bool
+Event_scheduler::init()
+{
+ int i= 0;
+ bool ret= FALSE;
+ DBUG_ENTER("Event_scheduler::init");
+ DBUG_PRINT("enter", ("this=%p", this));
+
+ LOCK_SCHEDULER_DATA();
+ for (;i < COND_LAST; i++)
+ if (pthread_cond_init(&cond_vars[i], NULL))
+ {
+ sql_print_error("SCHEDULER: Unable to initalize conditions");
+ ret= TRUE;
+ goto end;
+ }
+
+ /* init memory root */
+ init_alloc_root(&scheduler_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+
+ if (init_queue_ex(&queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
+ event_timed_compare_q, NULL, 30 /*auto_extent*/))
+ {
+ sql_print_error("SCHEDULER: Can't initialize the execution queue");
+ ret= TRUE;
+ goto end;
+ }
+
+ if (sizeof(my_time_t) != sizeof(time_t))
+ {
+ sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
+ "The scheduler may not work correctly. Stopping.");
+ DBUG_ASSERT(0);
+ ret= TRUE;
+ goto end;
+ }
+
+ state= INITIALIZED;
+end:
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Frees all memory allocated by the scheduler object.
+
+ SYNOPSIS
+ Event_scheduler::destroy()
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+*/
+
+void
+Event_scheduler::destroy()
+{
+ DBUG_ENTER("Event_scheduler");
+
+ LOCK_SCHEDULER_DATA();
+ switch (state) {
+ case UNINITIALIZED:
+ break;
+ case INITIALIZED:
+ delete_queue(&queue);
+ free_root(&scheduler_root, MYF(0));
+ int i;
+ for (i= 0; i < COND_LAST; i++)
+ pthread_cond_destroy(&cond_vars[i]);
+ state= UNINITIALIZED;
+ break;
+ default:
+ sql_print_error("SCHEDULER: Destroying while state is %d", state);
+ /* I trust my code but ::safe() > ::sorry() */
+ DBUG_ASSERT(0);
+ break;
+ }
+ UNLOCK_SCHEDULER_DATA();
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Adds an event to the scheduler queue
+
+ SYNOPSIS
+ Event_scheduler::add_event()
+ et The event to add
+ check_existence Whether to check if already loaded.
+
+ RETURN VALUE
+ OP_OK OK or scheduler not working
+ OP_LOAD_ERROR Error during loading from disk
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::add_event(THD *thd, Event_timed *et, bool check_existence)
+{
+ enum enum_error_code res;
+ Event_timed *et_new;
+ DBUG_ENTER("Event_scheduler::add_event");
+ DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
+
+ LOCK_SCHEDULER_DATA();
+ if (!is_running_or_suspended())
+ {
+ DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(OP_OK);
+ }
+ if (check_existence && find_event(et, FALSE))
+ {
+ res= OP_ALREADY_EXISTS;
+ goto end;
+ }
+
+ /* We need to load the event on scheduler_root */
+ if (!(res= load_named_event(thd, et, &et_new)))
+ {
+ queue_insert_safe(&queue, (byte *) et_new);
+ DBUG_PRINT("info", ("Sending COND_new_work"));
+ pthread_cond_signal(&cond_vars[COND_new_work]);
+ }
+ else if (res == OP_DISABLED_EVENT)
+ res= OP_OK;
+end:
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Drops an event from the scheduler queue
+
+ SYNOPSIS
+ Event_scheduler::drop_event()
+ etn The event to drop
+ state Wait the event or kill&drop
+
+ RETURN VALUE
+ FALSE OK (replaced or scheduler not working)
+ TRUE Failure
+*/
+
+bool
+Event_scheduler::drop_event(THD *thd, Event_timed *et)
+{
+ int res;
+ Event_timed *et_old;
+ DBUG_ENTER("Event_scheduler::drop_event");
+ DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
+
+ LOCK_SCHEDULER_DATA();
+ if (!is_running_or_suspended())
+ {
+ DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(OP_OK);
+ }
+
+ if (!(et_old= find_event(et, TRUE)))
+ DBUG_PRINT("info", ("No such event found, probably DISABLED"));
+
+ UNLOCK_SCHEDULER_DATA();
+
+ /* See comments in ::replace_event() why this is split in two parts. */
+ if (et_old)
+ {
+ switch ((res= et_old->kill_thread(thd))) {
+ case EVEX_CANT_KILL:
+ /* Don't delete but continue */
+ et_old->flags |= EVENT_FREE_WHEN_FINISHED;
+ break;
+ case 0:
+ /*
+ kill_thread() waits till the spawned thread finishes after it's
+ killed. Hence, we delete here memory which is no more referenced from
+ a running thread.
+ */
+ delete et_old;
+ /*
+ We don't signal COND_new_work here because:
+ 1. Even if the dropped event is on top of the queue this will not
+ move another one to be executed before the time the one on the
+ top (but could be at the same second as the dropped one)
+ 2. If this was the last event on the queue, then pthread_cond_timedwait
+ in ::run() will finish and then see that the queue is empty and
+ call cond_wait(). Hence, no need to interrupt the blocked
+ ::run() thread.
+ */
+ break;
+ default:
+ sql_print_error("SCHEDULER: Got unexpected error %d", res);
+ DBUG_ASSERT(0);
+ }
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Replaces an event in the scheduler queue
+
+ SYNOPSIS
+ Event_scheduler::replace_event()
+ et The event to replace(add) into the queue
+ state Async or sync stopping
+
+ RETURN VALUE
+ OP_OK OK or scheduler not working
+ OP_LOAD_ERROR Error during loading from disk
+ OP_ALREADY_EXISTS Event already in the queue
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::replace_event(THD *thd, Event_timed *et,
+ LEX_STRING *new_schema,
+ LEX_STRING *new_name)
+{
+ enum enum_error_code res;
+ Event_timed *et_old, *et_new= NULL;
+ LEX_STRING old_schema, old_name;
+
+ LINT_INIT(old_schema.str);
+ LINT_INIT(old_schema.length);
+ LINT_INIT(old_name.str);
+ LINT_INIT(old_name.length);
+
+ DBUG_ENTER("Event_scheduler::replace_event");
+ DBUG_PRINT("enter", ("thd=%p et=%p et=[%s.%s] lock=%p",
+ thd, et, et->dbname.str, et->name.str, &LOCK_scheduler_data));
+
+ LOCK_SCHEDULER_DATA();
+ if (!is_running_or_suspended())
+ {
+ DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(OP_OK);
+ }
+
+ if (!(et_old= find_event(et, TRUE)))
+ DBUG_PRINT("info", ("%s.%s not found cached, probably was DISABLED",
+ et->dbname.str, et->name.str));
+
+ if (new_schema && new_name)
+ {
+ old_schema= et->dbname;
+ old_name= et->name;
+ et->dbname= *new_schema;
+ et->name= *new_name;
+ }
+ /*
+ We need to load the event (it's strings but on the object itself)
+ on scheduler_root. et_new could be NULL :
+ 1. Error occured
+ 2. If the replace is DISABLED, we don't load it into the queue.
+ */
+ if (!(res= load_named_event(thd, et, &et_new)))
+ {
+ queue_insert_safe(&queue, (byte *) et_new);
+ DBUG_PRINT("info", ("Sending COND_new_work"));
+ pthread_cond_signal(&cond_vars[COND_new_work]);
+ }
+ else if (res == OP_DISABLED_EVENT)
+ res= OP_OK;
+
+ if (new_schema && new_name)
+ {
+ et->dbname= old_schema;
+ et->name= old_name;
+ }
+
+ UNLOCK_SCHEDULER_DATA();
+ /*
+ Andrey: Is this comment still truthful ???
+
+ We don't move this code above because a potential kill_thread will call
+ THD::awake(). Which in turn will try to acqure mysys_var->current_mutex,
+ which is LOCK_scheduler_data on which the COND_new_work in ::run() locks.
+ Hence, we try to acquire a lock which we have already acquired and we run
+ into an assert. Holding LOCK_scheduler_data however is not needed because
+ we don't touch any invariant of the scheduler anymore. ::drop_event() does
+ the same.
+ */
+ if (et_old)
+ {
+ switch (et_old->kill_thread(thd)) {
+ case EVEX_CANT_KILL:
+ /* Don't delete but continue */
+ et_old->flags |= EVENT_FREE_WHEN_FINISHED;
+ break;
+ case 0:
+ /*
+ kill_thread() waits till the spawned thread finishes after it's
+ killed. Hence, we delete here memory which is no more referenced from
+ a running thread.
+ */
+ delete et_old;
+ /*
+ We don't signal COND_new_work here because:
+ 1. Even if the dropped event is on top of the queue this will not
+ move another one to be executed before the time the one on the
+ top (but could be at the same second as the dropped one)
+ 2. If this was the last event on the queue, then pthread_cond_timedwait
+ in ::run() will finish and then see that the queue is empty and
+ call cond_wait(). Hence, no need to interrupt the blocked
+ ::run() thread.
+ */
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Searches for an event in the scheduler queue
+
+ SYNOPSIS
+ Event_scheduler::find_event()
+ etn The event to find
+ comparator The function to use for comparing
+ remove_from_q If found whether to remove from the Q
+
+ RETURN VALUE
+ NULL Not found
+ otherwise Address
+
+ NOTE
+ The caller should do the locking also the caller is responsible for
+ actual signalling in case an event is removed from the queue
+ (signalling COND_new_work for instance).
+*/
+
+Event_timed *
+Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
+{
+ uint i;
+ DBUG_ENTER("Event_scheduler::find_event");
+
+ for (i= 0; i < queue.elements; ++i)
+ {
+ Event_timed *et= (Event_timed *) queue_element(&queue, i);
+ DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", etn->dbname.str, etn->name.str,
+ et->dbname.str, et->name.str));
+ if (event_timed_identifier_equal(etn, et))
+ {
+ if (remove_from_q)
+ queue_remove(&queue, i);
+ DBUG_RETURN(et);
+ }
+ }
+
+ DBUG_RETURN(NULL);
+}
+
+
+/*
+ Drops all events from the in-memory queue and disk that match
+ certain pattern evaluated by a comparator function
+
+ SYNOPSIS
+ Event_scheduler::drop_matching_events()
+ thd THD
+ pattern A pattern string
+ comparator The function to use for comparing
+
+ RETURN VALUE
+ -1 Scheduler not working
+ >=0 Number of dropped events
+
+ NOTE
+ Expected is the caller to acquire lock on LOCK_scheduler_data
+*/
+
+void
+Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
+ bool (*comparator)(Event_timed *,LEX_STRING *))
+{
+ DBUG_ENTER("Event_scheduler::drop_matching_events");
+ DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern->length, pattern->str,
+ state));
+ if (is_running_or_suspended())
+ {
+ uint i= 0, dropped= 0;
+ while (i < queue.elements)
+ {
+ Event_timed *et= (Event_timed *) queue_element(&queue, i);
+ DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
+ if (comparator(et, pattern))
+ {
+ /*
+ The queue is ordered. If we remove an element, then all elements after
+ it will shift one position to the left, if we imagine it as an array
+ from left to the right. In this case we should not increment the
+ counter and the (i < queue.elements) condition is ok.
+ */
+ queue_remove(&queue, i);
+
+ /* See replace_event() */
+ switch (et->kill_thread(thd)) {
+ case EVEX_CANT_KILL:
+ /* Don't delete but continue */
+ et->flags |= EVENT_FREE_WHEN_FINISHED;
+ ++dropped;
+ break;
+ case 0:
+ delete et;
+ ++dropped;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ else
+ i++;
+ }
+ DBUG_PRINT("info", ("Dropped %lu", dropped));
+ }
+ /*
+ Don't send COND_new_work because no need to wake up the scheduler thread.
+ When it wakes next time up it will recalculate how much more it should
+ sleep if the top of the queue has been changed by this method.
+ */
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Drops all events from the in-memory queue and disk that are from
+ certain schema.
+
+ SYNOPSIS
+ Event_scheduler::drop_schema_events()
+ thd THD
+ db The schema name
+
+ RETURN VALUE
+ -1 Scheduler not working
+ >=0 Number of dropped events
+*/
+
+int
+Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
+{
+ int ret;
+ DBUG_ENTER("Event_scheduler::drop_schema_events");
+ LOCK_SCHEDULER_DATA();
+ if (is_running_or_suspended())
+ drop_matching_events(thd, schema, event_timed_db_equal);
+
+ ret= db_drop_events_from_table(thd, schema);
+ UNLOCK_SCHEDULER_DATA();
+
+ DBUG_RETURN(ret);
+}
+
+
+extern pthread_attr_t connection_attrib;
+
+
+/*
+ Starts the event scheduler
+
+ SYNOPSIS
+ Event_scheduler::start()
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+*/
+
+bool
+Event_scheduler::start()
+{
+ bool ret= FALSE;
+ pthread_t th;
+ DBUG_ENTER("Event_scheduler::start");
+
+ LOCK_SCHEDULER_DATA();
+ /* If already working or starting don't make another attempt */
+ DBUG_ASSERT(state == INITIALIZED);
+ if (state > INITIALIZED)
+ {
+ DBUG_PRINT("info", ("scheduler is already running or starting"));
+ ret= TRUE;
+ goto end;
+ }
+
+ /*
+ Now if another thread calls start it will bail-out because the branch
+ above will be executed. Thus no two or more child threads will be forked.
+ If the child thread cannot start for some reason then `state` is set
+ to CANTSTART and COND_started is also signaled. In this case we
+ set `state` back to INITIALIZED so another attempt to start the scheduler
+ can be made.
+ */
+ state= COMMENCING;
+ /* Fork */
+ if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
+ (void*)this))
+ {
+ DBUG_PRINT("error", ("cannot create a new thread"));
+ state= INITIALIZED;
+ ret= TRUE;
+ goto end;
+ }
+
+ /* Wait till the child thread has booted (w/ or wo success) */
+ while (!is_running_or_suspended() && state != CANTSTART)
+ cond_wait(COND_started_or_stopped, &LOCK_scheduler_data);
+
+ /*
+ If we cannot start for some reason then don't prohibit further attempts.
+ Set back to INITIALIZED.
+ */
+ if (state == CANTSTART)
+ {
+ state= INITIALIZED;
+ ret= TRUE;
+ goto end;
+ }
+
+end:
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Starts the event scheduler in suspended mode.
+
+ SYNOPSIS
+ Event_scheduler::start_suspended()
+
+ RETURN VALUE
+ TRUE OK
+ FALSE Error
+*/
+
+bool
+Event_scheduler::start_suspended()
+{
+ DBUG_ENTER("Event_scheduler::start_suspended");
+ start_scheduler_suspended= TRUE;
+ DBUG_RETURN(start());
+}
+
+
+
+/*
+ Report back that we cannot start. Used for ocasions where
+ we can't go into ::run() and have to report externally.
+
+ SYNOPSIS
+ Event_scheduler::report_error_during_start()
+*/
+
+inline void
+Event_scheduler::report_error_during_start()
+{
+ DBUG_ENTER("Event_scheduler::report_error_during_start");
+
+ LOCK_SCHEDULER_DATA();
+ state= CANTSTART;
+ DBUG_PRINT("info", ("Sending back COND_started_or_stopped"));
+ pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+ UNLOCK_SCHEDULER_DATA();
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ The internal loop of the event scheduler
+
+ SYNOPSIS
+ Event_scheduler::run()
+ thd Thread
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Failure
+*/
+
+bool
+Event_scheduler::run(THD *thd)
+{
+ int ret;
+ struct timespec abstime;
+ DBUG_ENTER("Event_scheduler::run");
+ DBUG_PRINT("enter", ("thd=%p", thd));
+
+ LOCK_SCHEDULER_DATA();
+ ret= load_events_from_db(thd);
+
+ if (!ret)
+ {
+ thread_id= thd->thread_id;
+ state= start_scheduler_suspended? SUSPENDED:RUNNING;
+ start_scheduler_suspended= FALSE;
+ }
+ else
+ state= CANTSTART;
+
+ DBUG_PRINT("info", ("Sending back COND_started_or_stopped"));
+ pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+ if (ret)
+ {
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(TRUE);
+ }
+ if (!check_n_suspend_if_needed(thd))
+ UNLOCK_SCHEDULER_DATA();
+
+ sql_print_information("SCHEDULER: Manager thread started with id %lu",
+ thd->thread_id);
+ abstime.tv_nsec= 0;
+ while (is_running_or_suspended())
+ {
+ Event_timed *et;
+
+ LOCK_SCHEDULER_DATA();
+ if (check_n_wait_for_non_empty_queue(thd))
+ continue;
+
+ /* On TRUE data is unlocked, go back to the beginning */
+ if (check_n_suspend_if_needed(thd))
+ continue;
+
+ /* Guaranteed locked here */
+ if (state == IN_SHUTDOWN || shutdown_in_progress)
+ {
+ UNLOCK_SCHEDULER_DATA();
+ break;
+ }
+ DBUG_ASSERT(state == RUNNING);
+
+ et= (Event_timed *)queue_top(&queue);
+
+ /* Skip disabled events */
+ if (et->status != Event_timed::ENABLED)
+ {
+ /*
+ It could be a one-timer scheduled for a time, already in the past when the
+ scheduler was suspended.
+ */
+ sql_print_information("SCHEDULER: Found a disabled event %*s.%*s in the queue",
+ et->dbname.length, et->dbname.str, et->name.length,
+ et->name.str);
+ queue_remove(&queue, 0);
+ /* ToDo: check this again */
+ if (et->dropped)
+ et->drop(thd);
+ delete et;
+ UNLOCK_SCHEDULER_DATA();
+ continue;
+ }
+ thd->proc_info= (char *)"Computing";
+ DBUG_PRINT("evex manager",("computing time to sleep till next exec"));
+ /* Timestamp is in UTC */
+ abstime.tv_sec= sec_since_epoch_TIME(&et->execute_at);
+
+ thd->end_time();
+ if (abstime.tv_sec > thd->query_start())
+ {
+ /* Event trigger time is in the future */
+ thd->proc_info= (char *)"Sleep";
+ DBUG_PRINT("info", ("Going to sleep. Should wakeup after approx %d secs",
+ abstime.tv_sec - thd->query_start()));
+ DBUG_PRINT("info", ("Entering condition because waiting for activation"));
+ /*
+ Use THD::enter_cond()/exit_cond() or we won't be able to kill a
+ sleeping thread. Though ::stop() can do it by sending COND_new_work
+ an user can't by just issuing 'KILL x'; . In the latter case
+ pthread_cond_timedwait() will wait till `abstime`.
+ "Sleeping until next time"
+ */
+ thd->enter_cond(&cond_vars[COND_new_work],&LOCK_scheduler_data,"Sleeping");
+
+ pthread_cond_timedwait(&cond_vars[COND_new_work], &LOCK_scheduler_data,
+ &abstime);
+
+ DBUG_PRINT("info", ("Manager woke up. state is %d", state));
+ /*
+ If we get signal we should recalculate the whether it's the right time
+ because there could be :
+ 1. Spurious wake-up
+ 2. The top of the queue was changed (new one becase of add/drop/replace)
+ */
+ /* This will do implicit UNLOCK_SCHEDULER_DATA() */
+ thd->exit_cond("");
+ }
+ else
+ {
+ thd->proc_info= (char *)"Executing";
+ /*
+ Execute the event. An error may occur if a thread cannot be forked.
+ In this case stop the manager.
+ We should enter ::execute_top() with locked LOCK_scheduler_data.
+ */
+ int ret= execute_top(thd);
+ UNLOCK_SCHEDULER_DATA();
+ if (ret)
+ break;
+ }
+ }
+
+ thd->proc_info= (char *)"Cleaning";
+
+ LOCK_SCHEDULER_DATA();
+ /*
+ It's possible that a user has used (SQL)COM_KILL. Hence set the appropriate
+ state because it is only set by ::stop().
+ */
+ if (state != IN_SHUTDOWN)
+ {
+ DBUG_PRINT("info", ("We got KILL but the but not from ::stop()"));
+ state= IN_SHUTDOWN;
+ }
+ UNLOCK_SCHEDULER_DATA();
+
+ sql_print_information("SCHEDULER: Shutting down");
+
+ thd->proc_info= (char *)"Cleaning queue";
+ clean_queue(thd);
+ THD_CHECK_SENTRY(thd);
+
+ /* free mamager_root memory but don't destroy the root */
+ thd->proc_info= (char *)"Cleaning memory root";
+ free_root(&scheduler_root, MYF(0));
+ THD_CHECK_SENTRY(thd);
+
+ /*
+ We notify the waiting thread which shutdowns us that we have cleaned.
+ There are few more instructions to be executed in this pthread but
+ they don't affect manager structures thus it's safe to signal already
+ at this point.
+ */
+ LOCK_SCHEDULER_DATA();
+ thd->proc_info= (char *)"Sending shutdown signal";
+ DBUG_PRINT("info", ("Sending COND_started_or_stopped"));
+ if (state == IN_SHUTDOWN)
+ pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+
+ state= INITIALIZED;
+ /*
+ We set it here because ::run() can stop not only because of ::stop()
+ call but also because of `KILL x`
+ */
+ thread_id= 0;
+ sql_print_information("SCHEDULER: Stopped");
+ UNLOCK_SCHEDULER_DATA();
+
+ /* We have modified, we set back */
+ thd->query= NULL;
+ thd->query_length= 0;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Executes the top element of the queue. Auxiliary method for ::run().
+
+ SYNOPSIS
+ Event_scheduler::execute_top()
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Failure
+
+ NOTE
+ NO locking is done. EXPECTED is that the caller should have locked
+ the queue (w/ LOCK_scheduler_data).
+*/
+
+bool
+Event_scheduler::execute_top(THD *thd)
+{
+ int spawn_ret_code;
+ bool ret= FALSE;
+ DBUG_ENTER("Event_scheduler::execute_top");
+ DBUG_PRINT("enter", ("thd=%p", thd));
+
+ Event_timed *et= (Event_timed *)queue_top(&queue);
+
+ /* Is it good idea to pass a stack address ?*/
+ Worker_thread_param param(et);
+
+ pthread_mutex_lock(&param.LOCK_started);
+ /*
+ We don't lock LOCK_scheduler_data fpr workers_increment() because it's a
+ pre-requisite for calling the current_method.
+ */
+ switch ((spawn_ret_code= et->spawn_now(event_worker_thread, &param))) {
+ case EVENT_EXEC_CANT_FORK:
+ /*
+ We don't lock LOCK_scheduler_data here because it's a pre-requisite
+ for calling the current_method.
+ */
+ sql_print_error("SCHEDULER: Problem while trying to create a thread");
+ ret= TRUE;
+ break;
+ case EVENT_EXEC_ALREADY_EXEC:
+ /*
+ We don't lock LOCK_scheduler_data here because it's a pre-requisite
+ for calling the current_method.
+ */
+ sql_print_information("SCHEDULER: %s.%s in execution. Skip this time.",
+ et->dbname.str, et->name.str);
+ if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == Event_timed::DISABLED)
+ queue_remove(&queue, 0);// 0 is top, internally 1
+ else
+ queue_replaced(&queue);
+ break;
+ default:
+ DBUG_ASSERT(!spawn_ret_code);
+ if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == Event_timed::DISABLED)
+ queue_remove(&queue, 0);// 0 is top, internally 1
+ else
+ queue_replaced(&queue);
+ /*
+ We don't lock LOCK_scheduler_data here because it's a pre-requisite
+ for calling the current_method.
+ */
+ if (likely(!spawn_ret_code))
+ {
+ /* Wait the forked thread to start */
+ do {
+ pthread_cond_wait(&param.COND_started, &param.LOCK_started);
+ } while (!param.started);
+ }
+ /*
+ param was allocated on the stack so no explicit delete as well as
+ in this moment it's no more used in the spawned thread so it's safe
+ to be deleted.
+ */
+ break;
+ }
+ pthread_mutex_unlock(&param.LOCK_started);
+ /* `param` is on the stack and will be destructed by the compiler */
+
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Cleans the scheduler's queue. Auxiliary method for ::run().
+
+ SYNOPSIS
+ Event_scheduler::clean_queue()
+ thd Thread
+*/
+
+void
+Event_scheduler::clean_queue(THD *thd)
+{
+ CHARSET_INFO *scs= system_charset_info;
+ uint i;
+ DBUG_ENTER("Event_scheduler::clean_queue");
+ DBUG_PRINT("enter", ("thd=%p", thd));
+
+ LOCK_SCHEDULER_DATA();
+ stop_all_running_events(thd);
+ UNLOCK_SCHEDULER_DATA();
+
+ sql_print_information("SCHEDULER: Emptying the queue");
+
+ /* empty the queue */
+ for (i= 0; i < queue.elements; ++i)
+ {
+ Event_timed *et= (Event_timed *) queue_element(&queue, i);
+ et->free_sp();
+ delete et;
+ }
+ resize_queue(&queue, 0);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Stops all running events
+
+ SYNOPSIS
+ Event_scheduler::stop_all_running_events()
+ thd Thread
+
+ NOTE
+ LOCK_scheduler data must be acquired prior to call to this method
+*/
+
+void
+Event_scheduler::stop_all_running_events(THD *thd)
+{
+ CHARSET_INFO *scs= system_charset_info;
+ uint i;
+ DYNAMIC_ARRAY running_threads;
+ THD *tmp;
+ DBUG_ENTER("Event_scheduler::stop_all_running_events");
+ DBUG_PRINT("enter", ("workers_count=%d", workers_count()));
+
+ my_init_dynamic_array(&running_threads, sizeof(ulong), 10, 10);
+
+ bool had_super= FALSE;
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ if (tmp->command == COM_DAEMON)
+ continue;
+ if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
+ push_dynamic(&running_threads, (gptr) &tmp->thread_id);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ /* We need temporarily SUPER_ACL to be able to kill our offsprings */
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
+ thd->security_ctx->master_access|= SUPER_ACL;
+ else
+ had_super= TRUE;
+
+ char tmp_buff[10*STRING_BUFFER_USUAL_SIZE];
+ char int_buff[STRING_BUFFER_USUAL_SIZE];
+ String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+ String int_string(int_buff, sizeof(int_buff), scs);
+ tmp_string.length(0);
+
+ for (i= 0; i < running_threads.elements; ++i)
+ {
+ int ret;
+ ulong thd_id= *dynamic_element(&running_threads, i, ulong*);
+
+ int_string.set((longlong) thd_id,scs);
+ tmp_string.append(int_string);
+ if (i < running_threads.elements - 1)
+ tmp_string.append(' ');
+
+ if ((ret= kill_one_thread(thd, thd_id, FALSE)))
+ {
+ sql_print_error("SCHEDULER: Error killing %lu code=%d", thd_id, ret);
+ break;
+ }
+ }
+ if (running_threads.elements)
+ sql_print_information("SCHEDULER: Killing workers :%s", tmp_string.c_ptr());
+
+ if (!had_super)
+ thd->security_ctx->master_access &= ~SUPER_ACL;
+
+ delete_dynamic(&running_threads);
+
+ sql_print_information("SCHEDULER: Waiting for worker threads to finish");
+
+ while (workers_count())
+ my_sleep(100000);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Stops the event scheduler
+
+ SYNOPSIS
+ Event_scheduler::stop()
+
+ RETURN VALUE
+ OP_OK OK
+ OP_CANT_KILL Error during stopping of manager thread
+ OP_NOT_RUNNING Manager not working
+
+ NOTE
+ The caller must have acquited LOCK_scheduler_data.
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::stop()
+{
+ THD *thd= current_thd;
+ DBUG_ENTER("Event_scheduler::stop");
+ DBUG_PRINT("enter", ("thd=%p", current_thd));
+
+ LOCK_SCHEDULER_DATA();
+ if (!is_running_or_suspended())
+ {
+ /*
+ One situation to be here is if there was a start that forked a new
+ thread but the new thread did not acquire yet LOCK_scheduler_data.
+ Hence, in this case return an error.
+ */
+ DBUG_PRINT("info", ("manager not running but %d. doing nothing", state));
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(OP_NOT_RUNNING);
+ }
+ state= IN_SHUTDOWN;
+
+ DBUG_PRINT("info", ("Manager thread has id %d", thread_id));
+ sql_print_information("SCHEDULER: Killing manager thread %lu", thread_id);
+
+ /*
+ Sending the COND_new_work to ::run() is a way to get this working without
+ race conditions. If we use kill_one_thread() it will call THD::awake() and
+ because in ::run() both THD::enter_cond()/::exit_cond() are used,
+ THD::awake() will try to lock LOCK_scheduler_data. If we UNLOCK it before,
+ then the pthread_cond_signal(COND_started_or_stopped) could be signaled in
+ ::run() and we can miss the signal before we relock. A way is to use
+ another mutex for this shutdown procedure but better not.
+ */
+ pthread_cond_signal(&cond_vars[COND_new_work]);
+ /* Or we are suspended - then we should wake up */
+ pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+
+ /* Guarantee we don't catch spurious signals */
+ sql_print_information("SCHEDULER: Waiting the manager thread to reply");
+ while (state != INITIALIZED)
+ {
+ DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from the manager "
+ "thread. Current value of state is %d . "
+ "workers count=%d", state, workers_count()));
+ cond_wait(COND_started_or_stopped, &LOCK_scheduler_data);
+ }
+ DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
+ UNLOCK_SCHEDULER_DATA();
+
+ DBUG_RETURN(OP_OK);
+}
+
+
+/*
+ Suspends or resumes the scheduler.
+ SUSPEND - it won't execute any event till resumed.
+ RESUME - it will resume if suspended.
+
+ SYNOPSIS
+ Event_scheduler::suspend_or_resume()
+
+ RETURN VALUE
+ OP_OK OK
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::suspend_or_resume(
+ enum Event_scheduler::enum_suspend_or_resume action)
+{
+ DBUG_ENTER("Event_scheduler::suspend_or_resume");
+ DBUG_PRINT("enter", ("action=%d", action));
+
+ LOCK_SCHEDULER_DATA();
+
+ if ((action == SUSPEND && state == SUSPENDED) ||
+ (action == RESUME && state == RUNNING))
+ {
+ DBUG_PRINT("info", ("Either trying to suspend suspended or resume "
+ "running scheduler. Doing nothing."));
+ }
+ else
+ {
+ /* Wake the main thread up if he is asleep */
+ DBUG_PRINT("info", ("Sending signal"));
+ if (action==SUSPEND)
+ {
+ state= SUSPENDED;
+ pthread_cond_signal(&cond_vars[COND_new_work]);
+ }
+ else
+ {
+ state= RUNNING;
+ pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+ }
+ DBUG_PRINT("info", ("Waiting on COND_suspend_or_resume"));
+ cond_wait(COND_suspend_or_resume, &LOCK_scheduler_data);
+ DBUG_PRINT("info", ("Got response"));
+ }
+ UNLOCK_SCHEDULER_DATA();
+ DBUG_RETURN(OP_OK);
+}
+
+
+/*
+ Returns the number of executing events.
+
+ SYNOPSIS
+ Event_scheduler::workers_count()
+*/
+
+uint
+Event_scheduler::workers_count()
+{
+ THD *tmp;
+ uint count= 0;
+
+ DBUG_ENTER("Event_scheduler::workers_count");
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ if (tmp->command == COM_DAEMON)
+ continue;
+ if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
+ ++count;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ DBUG_PRINT("exit", ("%d", count));
+ DBUG_RETURN(count);
+}
+
+
+/*
+ Checks and suspends if needed
+
+ SYNOPSIS
+ Event_scheduler::check_n_suspend_if_needed()
+ thd Thread
+
+ RETURN VALUE
+ FALSE Not suspended, we haven't slept
+ TRUE We were suspended. LOCK_scheduler_data is unlocked.
+
+ NOTE
+ The caller should have locked LOCK_scheduler_data!
+ The mutex will be unlocked in case this function returns TRUE
+*/
+
+bool
+Event_scheduler::check_n_suspend_if_needed(THD *thd)
+{
+ bool was_suspended= FALSE;
+ DBUG_ENTER("Event_scheduler::check_n_suspend_if_needed");
+ if (thd->killed && !shutdown_in_progress)
+ {
+ state= SUSPENDED;
+ thd->killed= THD::NOT_KILLED;
+ }
+ if (state == SUSPENDED)
+ {
+ thd->enter_cond(&cond_vars[COND_suspend_or_resume], &LOCK_scheduler_data,
+ "Suspended");
+ /* Send back signal to the thread that asked us to suspend operations */
+ pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+ sql_print_information("SCHEDULER: Suspending operations");
+ was_suspended= TRUE;
+ }
+ while (state == SUSPENDED)
+ {
+ cond_wait(COND_suspend_or_resume, &LOCK_scheduler_data);
+ DBUG_PRINT("info", ("Woke up after waiting on COND_suspend_or_resume"));
+ if (state != SUSPENDED)
+ {
+ pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+ sql_print_information("SCHEDULER: Resuming operations");
+ }
+ }
+ if (was_suspended)
+ {
+ if (queue.elements)
+ {
+ uint i;
+ DBUG_PRINT("info", ("We have to recompute the execution times"));
+
+ for (i= 0; i < queue.elements; i++)
+ {
+ ((Event_timed*)queue_element(&queue, i))->compute_next_execution_time();
+ ((Event_timed*)queue_element(&queue, i))->update_fields(thd);
+ }
+ queue_fix(&queue);
+ }
+ /* This will implicitly unlock LOCK_scheduler_data */
+ thd->exit_cond("");
+ }
+ DBUG_RETURN(was_suspended);
+}
+
+
+/*
+ Checks for empty queue and waits till new element gets in
+
+ SYNOPSIS
+ Event_scheduler::check_n_wait_for_non_empty_queue()
+ thd Thread
+
+ RETURN VALUE
+ FALSE Did not wait - LOCK_scheduler_data still locked.
+ TRUE Waited - LOCK_scheduler_data unlocked.
+
+ NOTE
+ The caller should have locked LOCK_scheduler_data!
+*/
+
+bool
+Event_scheduler::check_n_wait_for_non_empty_queue(THD *thd)
+{
+ bool slept= FALSE;
+ DBUG_ENTER("Event_scheduler::check_n_wait_for_non_empty_queue");
+ DBUG_PRINT("enter", ("q.elements=%lu state=%s",
+ queue.elements, states_names[state]));
+
+ if (!queue.elements)
+ thd->enter_cond(&cond_vars[COND_new_work], &LOCK_scheduler_data,
+ "Empty queue, sleeping");
+
+ /* Wait in a loop protecting against catching spurious signals */
+ while (!queue.elements && state == RUNNING)
+ {
+ slept= TRUE;
+ DBUG_PRINT("info", ("Entering condition because of empty queue"));
+ cond_wait(COND_new_work, &LOCK_scheduler_data);
+ DBUG_PRINT("info", ("Manager woke up. Hope we have events now. state=%d",
+ state));
+ /*
+ exit_cond does implicit mutex_UNLOCK, we needed it locked if
+ 1. we loop again
+ 2. end the current loop and start doing calculations
+ */
+ }
+ if (slept)
+ thd->exit_cond("");
+
+ DBUG_PRINT("exit", ("q.elements=%lu state=%s thd->killed=%d",
+ queue.elements, states_names[state], thd->killed));
+
+ DBUG_RETURN(slept);
+}
+
+
+/*
+ Wrapper for pthread_mutex_lock
+
+ SYNOPSIS
+ Event_scheduler::lock_data()
+ mutex Mutex to lock
+ line The line number on which the lock is done
+
+ RETURN VALUE
+ Error code of pthread_mutex_lock()
+*/
+
+inline void
+Event_scheduler::lock_data(const char *func, uint line)
+{
+ DBUG_ENTER("Event_scheduler::lock_mutex");
+ DBUG_PRINT("enter", ("mutex_lock=%p func=%s line=%u",
+ &LOCK_scheduler_data, func, line));
+ pthread_mutex_lock(&LOCK_scheduler_data);
+ mutex_last_locked_in_func= func;
+ mutex_last_locked_at_line= line;
+ mutex_scheduler_data_locked= TRUE;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Wrapper for pthread_mutex_unlock
+
+ SYNOPSIS
+ Event_scheduler::unlock_data()
+ mutex Mutex to unlock
+ line The line number on which the unlock is done
+*/
+
+inline void
+Event_scheduler::unlock_data(const char *func, uint line)
+{
+ DBUG_ENTER("Event_scheduler::UNLOCK_mutex");
+ DBUG_PRINT("enter", ("mutex_unlock=%p func=%s line=%u",
+ &LOCK_scheduler_data, func, line));
+ mutex_last_unlocked_at_line= line;
+ mutex_scheduler_data_locked= FALSE;
+ mutex_last_unlocked_in_func= func;
+ pthread_mutex_unlock(&LOCK_scheduler_data);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Wrapper for pthread_cond_wait
+
+ SYNOPSIS
+ Event_scheduler::cond_wait()
+ cond Conditional to wait for
+ mutex Mutex of the conditional
+
+ RETURN VALUE
+ Error code of pthread_cond_wait()
+*/
+
+inline int
+Event_scheduler::cond_wait(enum Event_scheduler::enum_cond_vars cond,
+ pthread_mutex_t *mutex)
+{
+ int ret;
+ DBUG_ENTER("Event_scheduler::cond_wait");
+ DBUG_PRINT("enter", ("cond=%s mutex=%p", cond_vars_names[cond], mutex));
+ ret= pthread_cond_wait(&cond_vars[cond_waiting_on=cond], mutex);
+ cond_waiting_on= COND_NONE;
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Checks whether the scheduler is in a running or suspended state.
+
+ SYNOPSIS
+ Event_scheduler::is_running_or_suspended()
+
+ RETURN VALUE
+ TRUE Either running or suspended
+ FALSE IN_SHUTDOWN, not started, etc.
+*/
+
+inline bool
+Event_scheduler::is_running_or_suspended()
+{
+ return (state == SUSPENDED || state == RUNNING);
+}
+
+
+/*
+ Returns the current state of the scheduler
+
+ SYNOPSIS
+ Event_scheduler::get_state()
+*/
+
+enum Event_scheduler::enum_state
+Event_scheduler::get_state()
+{
+ enum Event_scheduler::enum_state ret;
+ DBUG_ENTER("Event_scheduler::get_state");
+ /* lock_data & unlock_data are not static */
+ pthread_mutex_lock(&singleton.LOCK_scheduler_data);
+ ret= singleton.state;
+ pthread_mutex_unlock(&singleton.LOCK_scheduler_data);
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Returns whether the scheduler was initialized.
+
+ SYNOPSIS
+ Event_scheduler::initialized()
+
+ RETURN VALUE
+ FALSE Was not initialized so far
+ TRUE Was initialized
+*/
+
+bool
+Event_scheduler::initialized()
+{
+ DBUG_ENTER("Event_scheduler::initialized");
+ DBUG_RETURN(Event_scheduler::get_state() != UNINITIALIZED);
+}
+
+
+/*
+ Returns the number of elements in the queue
+
+ SYNOPSIS
+ Event_scheduler::events_count()
+
+ RETURN VALUE
+ 0 Number of Event_timed objects in the queue
+*/
+
+uint
+Event_scheduler::events_count()
+{
+ uint n;
+ DBUG_ENTER("Event_scheduler::events_count");
+ LOCK_SCHEDULER_DATA();
+ n= queue.elements;
+ UNLOCK_SCHEDULER_DATA();
+
+ DBUG_RETURN(n);
+}
+
+
+/*
+ Looks for a named event in mysql.event and then loads it from
+ the table, compiles and inserts it into the cache.
+
+ SYNOPSIS
+ Event_scheduler::load_named_event()
+ thd THD
+ etn The name of the event to load and compile on scheduler's root
+ etn_new The loaded event
+
+ RETURN VALUE
+ NULL Error during compile or the event is non-enabled.
+ otherwise Address
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new)
+{
+ int ret= 0;
+ MEM_ROOT *tmp_mem_root;
+ Event_timed *et_loaded= NULL;
+ Open_tables_state backup;
+
+ DBUG_ENTER("Event_scheduler::load_and_compile_event");
+ DBUG_PRINT("enter",("thd=%p name:%*s",thd, etn->name.length, etn->name.str));
+
+ thd->reset_n_backup_open_tables_state(&backup);
+ /* No need to use my_error() here because db_find_event() has done it */
+ {
+ sp_name spn(etn->dbname, etn->name);
+ ret= db_find_event(thd, &spn, &et_loaded, NULL, &scheduler_root);
+ }
+ thd->restore_backup_open_tables_state(&backup);
+ /* In this case no memory was allocated so we don't need to clean */
+ if (ret)
+ DBUG_RETURN(OP_LOAD_ERROR);
+
+ if (et_loaded->status != Event_timed::ENABLED)
+ {
+ /*
+ We don't load non-enabled events.
+ In db_find_event() `et_new` was allocated on the heap and not on
+ scheduler_root therefore we delete it here.
+ */
+ delete et_loaded;
+ DBUG_RETURN(OP_DISABLED_EVENT);
+ }
+
+ et_loaded->compute_next_execution_time();
+ *etn_new= et_loaded;
+
+ DBUG_RETURN(OP_OK);
+}
+
+
+/*
+ Loads all ENABLED events from mysql.event into the prioritized
+ queue. Called during scheduler main thread initialization. Compiles
+ the events. Creates Event_timed instances for every ENABLED event
+ from mysql.event.
+
+ SYNOPSIS
+ Event_scheduler::load_events_from_db()
+ thd - Thread context. Used for memory allocation in some cases.
+
+ RETURN VALUE
+ 0 OK
+ !0 Error (EVEX_OPEN_TABLE_FAILED, EVEX_MICROSECOND_UNSUP,
+ EVEX_COMPILE_ERROR) - in all these cases mysql.event was
+ tampered.
+
+ NOTES
+ Reports the error to the console
+*/
+
+int
+Event_scheduler::load_events_from_db(THD *thd)
+{
+ TABLE *table;
+ READ_RECORD read_record_info;
+ int ret= -1;
+ uint count= 0;
+ bool clean_the_queue= FALSE;
+ /* Compile the events on this root but only for syntax check, then discard */
+ MEM_ROOT boot_root;
+
+ DBUG_ENTER("Event_scheduler::load_events_from_db");
+ DBUG_PRINT("enter", ("thd=%p", thd));
+
+ if (state > COMMENCING)
+ {
+ DBUG_ASSERT(0);
+ sql_print_error("SCHEDULER: Trying to load events while already running.");
+ DBUG_RETURN(EVEX_GENERAL_ERROR);
+ }
+
+ if ((ret= Events::open_event_table(thd, TL_READ, &table)))
+ {
+ sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
+ DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
+ }
+
+ init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ init_read_record(&read_record_info, thd, table ,NULL,1,0);
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ Event_timed *et;
+ if (!(et= new Event_timed))
+ {
+ DBUG_PRINT("info", ("Out of memory"));
+ clean_the_queue= TRUE;
+ break;
+ }
+ DBUG_PRINT("info", ("Loading event from row."));
+
+ if ((ret= et->load_from_row(&scheduler_root, table)))
+ {
+ clean_the_queue= TRUE;
+ sql_print_error("SCHEDULER: Error while loading from mysql.event. "
+ "Table probably corrupted");
+ break;
+ }
+ if (et->status != Event_timed::ENABLED)
+ {
+ DBUG_PRINT("info",("%s is disabled",et->name.str));
+ delete et;
+ continue;
+ }
+
+ DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
+
+ /* We load only on scheduler root just to check whether the body compiles */
+ switch (ret= et->compile(thd, &boot_root)) {
+ case EVEX_MICROSECOND_UNSUP:
+ et->free_sp();
+ sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
+ "supported but found in mysql.event");
+ goto end;
+ case EVEX_COMPILE_ERROR:
+ sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
+ et->dbname.str, et->name.str);
+ goto end;
+ default:
+ /* Free it, it will be compiled again on the worker thread */
+ et->free_sp();
+ break;
+ }
+
+ /* let's find when to be executed */
+ if (et->compute_next_execution_time())
+ {
+ sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
+ " Skipping", et->dbname.str, et->name.str);
+ continue;
+ }
+
+ DBUG_PRINT("load_events_from_db", ("Adding %p to the exec list."));
+ queue_insert_safe(&queue, (byte *) et);
+ count++;
+ }
+end:
+ end_read_record(&read_record_info);
+ free_root(&boot_root, MYF(0));
+
+ if (clean_the_queue)
+ {
+ for (count= 0; count < queue.elements; ++count)
+ queue_remove(&queue, 0);
+ ret= -1;
+ }
+ else
+ {
+ ret= 0;
+ sql_print_information("SCHEDULER: Loaded %d event%s", count, (count == 1)?"":"s");
+ }
+
+ /* Force close to free memory */
+ thd->version--;
+
+ close_thread_tables(thd);
+
+ DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Opens mysql.db and mysql.user and checks whether:
+ 1. mysql.db has column Event_priv at column 20 (0 based);
+ 2. mysql.user has column Event_priv at column 29 (0 based);
+
+ SYNOPSIS
+ Event_scheduler::check_system_tables()
+*/
+
+bool
+Event_scheduler::check_system_tables(THD *thd)
+{
+ TABLE_LIST tables;
+ bool not_used;
+ Open_tables_state backup;
+ bool ret;
+
+ DBUG_ENTER("Event_scheduler::check_system_tables");
+ DBUG_PRINT("enter", ("thd=%p", thd));
+
+ thd->reset_n_backup_open_tables_state(&backup);
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*) "db";
+ tables.lock_type= TL_READ;
+
+ if ((ret= simple_open_n_lock_tables(thd, &tables)))
+ sql_print_error("Cannot open mysql.db");
+ else
+ {
+ ret= table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT,
+ mysql_db_table_fields, &mysql_db_table_last_check,
+ ER_CANNOT_LOAD_FROM_TABLE);
+ close_thread_tables(thd);
+ }
+ if (ret)
+ DBUG_RETURN(TRUE);
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*) "user";
+ tables.lock_type= TL_READ;
+
+ if ((ret= simple_open_n_lock_tables(thd, &tables)))
+ sql_print_error("Cannot open mysql.db");
+ else
+ {
+ if (tables.table->s->fields < 29 ||
+ strncmp(tables.table->field[29]->field_name,
+ STRING_WITH_LEN("Event_priv")))
+ {
+ sql_print_error("mysql.user has no `Event_priv` column at position 29");
+ ret= TRUE;
+ }
+ close_thread_tables(thd);
+ }
+
+ thd->restore_backup_open_tables_state(&backup);
+
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Inits mutexes.
+
+ SYNOPSIS
+ Event_scheduler::init_mutexes()
+*/
+
+void
+Event_scheduler::init_mutexes()
+{
+ pthread_mutex_init(&singleton.LOCK_scheduler_data, MY_MUTEX_INIT_FAST);
+}
+
+
+/*
+ Destroys mutexes.
+
+ SYNOPSIS
+ Event_scheduler::destroy_mutexes()
+*/
+
+void
+Event_scheduler::destroy_mutexes()
+{
+ pthread_mutex_destroy(&singleton.LOCK_scheduler_data);
+}
+
+
+/*
+ Dumps some data about the internal status of the scheduler.
+
+ SYNOPSIS
+ Event_scheduler::dump_internal_status()
+ thd THD
+
+ RETURN VALUE
+ 0 OK
+ 1 Error
+*/
+
+int
+Event_scheduler::dump_internal_status(THD *thd)
+{
+ DBUG_ENTER("dump_internal_status");
+#ifndef DBUG_OFF
+ CHARSET_INFO *scs= system_charset_info;
+ Protocol *protocol= thd->protocol;
+ List<Item> field_list;
+ int ret;
+ char tmp_buff[5*STRING_BUFFER_USUAL_SIZE];
+ char int_buff[STRING_BUFFER_USUAL_SIZE];
+ String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+ String int_string(int_buff, sizeof(int_buff), scs);
+ tmp_string.length(0);
+ int_string.length(0);
+
+ field_list.push_back(new Item_empty_string("Name", 20));
+ field_list.push_back(new Item_empty_string("Value",20));
+ if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ DBUG_RETURN(1);
+
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("state"), scs);
+ protocol->store(states_names[singleton.state].str,
+ states_names[singleton.state].length,
+ scs);
+
+ ret= protocol->write();
+ /*
+ If not initialized - don't show anything else. get_instance()
+ will otherwise implicitly initialize it. We don't want that.
+ */
+ if (singleton.state >= INITIALIZED)
+ {
+ /* last locked at*/
+ /*
+ The first thing to do, or get_instance() will overwrite the values.
+ mutex_last_locked_at_line / mutex_last_unlocked_at_line
+ */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("last locked at"), scs);
+ tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+ tmp_string.alloced_length(), "%s::%d",
+ singleton.mutex_last_locked_in_func,
+ singleton.mutex_last_locked_at_line));
+ protocol->store(&tmp_string);
+ ret= protocol->write();
+
+ /* last unlocked at*/
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("last unlocked at"), scs);
+ tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+ tmp_string.alloced_length(), "%s::%d",
+ singleton.mutex_last_unlocked_in_func,
+ singleton.mutex_last_unlocked_at_line));
+ protocol->store(&tmp_string);
+ ret= protocol->write();
+
+ /* waiting on */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("waiting on condition"), scs);
+ tmp_string.length(scs->cset->
+ snprintf(scs, (char*) tmp_string.ptr(),
+ tmp_string.alloced_length(), "%s",
+ (singleton.cond_waiting_on != COND_NONE) ?
+ cond_vars_names[singleton.cond_waiting_on]:
+ "NONE"));
+ protocol->store(&tmp_string);
+ ret= protocol->write();
+
+ Event_scheduler *scheduler= get_instance();
+
+ /* workers_count */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("workers_count"), scs);
+ int_string.set((longlong) scheduler->workers_count(), scs);
+ protocol->store(&int_string);
+ ret= protocol->write();
+
+ /* queue.elements */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("queue.elements"), scs);
+ int_string.set((longlong) scheduler->queue.elements, scs);
+ protocol->store(&int_string);
+ ret= protocol->write();
+
+ /* scheduler_data_locked */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("scheduler data locked"), scs);
+ int_string.set((longlong) scheduler->mutex_scheduler_data_locked, scs);
+ protocol->store(&int_string);
+ ret= protocol->write();
+ }
+ send_eof(thd);
+#endif
+ DBUG_RETURN(0);
+}
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h
new file mode 100644
index 00000000000..dffd47539fa
--- /dev/null
+++ b/sql/event_scheduler.h
@@ -0,0 +1,254 @@
+#ifndef _EVENT_SCHEDULER_H_
+#define _EVENT_SCHEDULER_H_
+/* Copyright (C) 2004-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 */
+
+
+class THD;
+typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
+
+int
+events_init();
+
+void
+events_shutdown();
+
+
+class Event_scheduler
+{
+public:
+ /* Return codes */
+ enum enum_error_code
+ {
+ OP_OK= 0,
+ OP_NOT_RUNNING,
+ OP_CANT_KILL,
+ OP_CANT_INIT,
+ OP_DISABLED_EVENT,
+ OP_LOAD_ERROR,
+ OP_ALREADY_EXISTS
+ };
+
+ enum enum_state
+ {
+ UNINITIALIZED= 0,
+ INITIALIZED,
+ COMMENCING,
+ CANTSTART,
+ RUNNING,
+ SUSPENDED,
+ IN_SHUTDOWN
+ };
+
+ enum enum_suspend_or_resume
+ {
+ SUSPEND= 1,
+ RESUME= 2
+ };
+
+ /* Singleton access */
+ static Event_scheduler*
+ get_instance();
+
+ /* Methods for queue management follow */
+
+ enum enum_error_code
+ add_event(THD *thd, Event_timed *et, bool check_existence);
+
+ bool
+ drop_event(THD *thd, Event_timed *et);
+
+ enum enum_error_code
+ replace_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
+ LEX_STRING *new_name);
+
+ int
+ drop_schema_events(THD *thd, LEX_STRING *schema);
+
+ int
+ drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num)
+ { DBUG_ASSERT(0); return 0;}
+
+ uint
+ events_count();
+
+ /* State changing methods follow */
+
+ bool
+ start();
+
+ enum enum_error_code
+ stop();
+
+ bool
+ start_suspended();
+
+ bool
+ run(THD *thd);
+
+ enum enum_error_code
+ suspend_or_resume(enum enum_suspend_or_resume action);
+
+ bool
+ init();
+
+ void
+ destroy();
+
+ static void
+ init_mutexes();
+
+ static void
+ destroy_mutexes();
+
+ void
+ report_error_during_start();
+
+ /* Information retrieving methods follow */
+
+ enum enum_state
+ get_state();
+
+ bool
+ initialized();
+
+ static int
+ dump_internal_status(THD *thd);
+
+ static bool
+ check_system_tables(THD *thd);
+
+private:
+ Event_timed *
+ find_event(Event_timed *etn, bool remove_from_q);
+
+ uint
+ workers_count();
+
+ bool
+ is_running_or_suspended();
+
+ /* helper functions */
+ bool
+ execute_top(THD *thd);
+
+ void
+ clean_queue(THD *thd);
+
+ void
+ stop_all_running_events(THD *thd);
+
+ enum enum_error_code
+ load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
+
+ int
+ load_events_from_db(THD *thd);
+
+ void
+ drop_matching_events(THD *thd, LEX_STRING *pattern,
+ bool (*)(Event_timed *,LEX_STRING *));
+
+ bool
+ check_n_suspend_if_needed(THD *thd);
+
+ bool
+ check_n_wait_for_non_empty_queue(THD *thd);
+
+ /* Singleton DP is used */
+ Event_scheduler();
+
+ enum enum_cond_vars
+ {
+ COND_NONE= -1,
+ /*
+ COND_new_work is a conditional used to signal that there is a change
+ of the queue that should inform the executor thread that new event should
+ be executed sooner than previously expected, because of add/replace event.
+ */
+ COND_new_work= 0,
+ /*
+ COND_started is a conditional used to synchronize the thread in which
+ ::start() was called and the spawned thread. ::start() spawns a new thread
+ and then waits on COND_started but also checks when awaken that `state` is
+ either RUNNING or CANTSTART. Then it returns back.
+ */
+ COND_started_or_stopped,
+ /*
+ Conditional used for signalling from the scheduler thread back to the
+ thread that calls ::suspend() or ::resume. Synchronizing the calls.
+ */
+ COND_suspend_or_resume,
+ /* Must be always last */
+ COND_LAST
+ };
+
+ /* Singleton instance */
+ static Event_scheduler singleton;
+
+ /* This is the current status of the life-cycle of the manager. */
+ enum enum_state state;
+
+ /* Set to start the scheduler in suspended state */
+ bool start_scheduler_suspended;
+
+ /*
+ LOCK_scheduler_data is the mutex which protects the access to the
+ manager's queue as well as used when signalling COND_new_work,
+ COND_started and COND_shutdown.
+ */
+ pthread_mutex_t LOCK_scheduler_data;
+
+ /*
+ Holds the thread id of the executor thread or 0 if the executor is not
+ running. It is used by ::shutdown() to know which thread to kill with
+ kill_one_thread(). The latter wake ups a thread if it is waiting on a
+ conditional variable and sets thd->killed to non-zero.
+ */
+ ulong thread_id;
+
+ pthread_cond_t cond_vars[COND_LAST];
+ static const char * const cond_vars_names[COND_LAST];
+
+ /* The MEM_ROOT of the object */
+ MEM_ROOT scheduler_root;
+
+ /* The sorted queue with the Event_timed objects */
+ QUEUE queue;
+
+ uint mutex_last_locked_at_line;
+ uint mutex_last_unlocked_at_line;
+ const char* mutex_last_locked_in_func;
+ const char* mutex_last_unlocked_in_func;
+ enum enum_cond_vars cond_waiting_on;
+ bool mutex_scheduler_data_locked;
+
+ /* helper functions for working with mutexes & conditionals */
+ void
+ lock_data(const char *func, uint line);
+
+ void
+ unlock_data(const char *func, uint line);
+
+ int
+ cond_wait(enum enum_cond_vars, pthread_mutex_t *mutex);
+
+private:
+ /* Prevent use of these */
+ Event_scheduler(const Event_scheduler &);
+ void operator=(Event_scheduler &);
+};
+
+#endif /* _EVENT_SCHEDULER_H_ */
diff --git a/sql/event_timed.cc b/sql/event_timed.cc
index 879f4d6a3c9..d6d6dddf971 100644
--- a/sql/event_timed.cc
+++ b/sql/event_timed.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2005 MySQL AB
+/* Copyright (C) 2004-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
@@ -17,7 +17,82 @@
#define MYSQL_LEX 1
#include "event_priv.h"
#include "event.h"
-#include "sp.h"
+#include "sp_head.h"
+
+
+/*
+ Constructor
+
+ SYNOPSIS
+ Event_timed::Event_timed()
+*/
+
+Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
+ running(0), thread_id(0), status_changed(false),
+ last_executed_changed(false), expression(0),
+ created(0), modified(0),
+ on_completion(Event_timed::ON_COMPLETION_DROP),
+ status(Event_timed::ENABLED), sphead(0),
+ sql_mode(0), body_begin(0), dropped(false),
+ free_sphead_on_delete(true), flags(0)
+
+{
+ pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&this->COND_finished, NULL);
+ init();
+}
+
+
+/*
+ Destructor
+
+ SYNOPSIS
+ Event_timed::~Event_timed()
+*/
+
+Event_timed::~Event_timed()
+{
+ deinit_mutexes();
+
+ if (free_sphead_on_delete)
+ free_sp();
+}
+
+
+/*
+ Destructor
+
+ SYNOPSIS
+ Event_timed::~deinit_mutexes()
+*/
+
+void
+Event_timed::deinit_mutexes()
+{
+ pthread_mutex_destroy(&this->LOCK_running);
+ pthread_cond_destroy(&this->COND_finished);
+}
+
+
+/*
+ Checks whether the event is running
+
+ SYNOPSIS
+ Event_timed::is_running()
+*/
+
+bool
+Event_timed::is_running()
+{
+ bool ret;
+
+ VOID(pthread_mutex_lock(&this->LOCK_running));
+ ret= running;
+ VOID(pthread_mutex_unlock(&this->LOCK_running));
+
+ return ret;
+}
+
/*
Init all member variables
@@ -238,7 +313,7 @@ Event_timed::init_execute_at(THD *thd, Item *expr)
expr how much?
new_interval what is the interval
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS Interval is not positive
@@ -249,7 +324,7 @@ int
Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
{
String value;
- INTERVAL interval;
+ INTERVAL interval_tmp;
DBUG_ENTER("Event_timed::init_interval");
@@ -257,71 +332,74 @@ Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
DBUG_RETURN(EVEX_PARSE_ERROR);
value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
- if (get_interval_value(expr, new_interval, &value, &interval))
+ if (get_interval_value(expr, new_interval, &value, &interval_tmp))
DBUG_RETURN(EVEX_PARSE_ERROR);
expression= 0;
switch (new_interval) {
case INTERVAL_YEAR:
- expression= interval.year;
+ expression= interval_tmp.year;
break;
case INTERVAL_QUARTER:
case INTERVAL_MONTH:
- expression= interval.month;
+ expression= interval_tmp.month;
break;
case INTERVAL_WEEK:
case INTERVAL_DAY:
- expression= interval.day;
+ expression= interval_tmp.day;
break;
case INTERVAL_HOUR:
- expression= interval.hour;
+ expression= interval_tmp.hour;
break;
case INTERVAL_MINUTE:
- expression= interval.minute;
+ expression= interval_tmp.minute;
break;
case INTERVAL_SECOND:
- expression= interval.second;
+ expression= interval_tmp.second;
break;
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
- expression= interval.year* 12 + interval.month;
+ expression= interval_tmp.year* 12 + interval_tmp.month;
break;
case INTERVAL_DAY_HOUR:
- expression= interval.day* 24 + interval.hour;
+ expression= interval_tmp.day* 24 + interval_tmp.hour;
break;
case INTERVAL_DAY_MINUTE:
- expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
+ expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 +
+ interval_tmp.minute;
break;
case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
case INTERVAL_DAY_SECOND:
/* DAY_SECOND having problems because of leap seconds? */
- expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
- + interval.second;
+ expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 +
+ interval_tmp.minute)*60
+ + interval_tmp.second;
break;
case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */
case INTERVAL_HOUR_MICROSECOND: /* day is anyway 0 */
case INTERVAL_DAY_MICROSECOND:
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
- expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
- interval.second) * 1000000L + interval.second_part;
+ expression= ((((interval_tmp.day*24) + interval_tmp.hour)*60+
+ interval_tmp.minute)*60 +
+ interval_tmp.second) * 1000000L + interval_tmp.second_part;
break;
case INTERVAL_HOUR_MINUTE:
- expression= interval.hour * 60 + interval.minute;
+ expression= interval_tmp.hour * 60 + interval_tmp.minute;
break;
case INTERVAL_MINUTE_SECOND:
- expression= interval.minute * 60 + interval.second;
+ expression= interval_tmp.minute * 60 + interval_tmp.second;
break;
case INTERVAL_SECOND_MICROSECOND:
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
- expression= interval.second * 1000000L + interval.second_part;
+ expression= interval_tmp.second * 1000000L + interval_tmp.second_part;
break;
case INTERVAL_MICROSECOND:
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
}
- if (interval.neg || expression > EVEX_MAX_INTERVAL_VALUE)
+ if (interval_tmp.neg || expression > EVEX_MAX_INTERVAL_VALUE)
DBUG_RETURN(EVEX_BAD_PARAMS);
- this->interval= new_interval;
+ interval= new_interval;
DBUG_RETURN(0);
}
@@ -342,7 +420,7 @@ Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
same time.
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS starts before now
@@ -408,7 +486,7 @@ Event_timed::init_starts(THD *thd, Item *new_starts)
DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
same time.
- RETURNS
+ RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
ER_WRONG_VALUE starts distant date (after year 2037)
@@ -492,6 +570,9 @@ Event_timed::init_comment(THD *thd, LEX_STRING *set_comment)
SYNOPSIS
Event_timed::init_definer()
+
+ RETURN VALUE
+ 0 OK
*/
int
@@ -534,6 +615,10 @@ Event_timed::init_definer(THD *thd)
SYNOPSIS
Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+ RETURN VALUE
+ 0 OK
+ EVEX_GET_FIELD_FAILED Error
+
NOTES
This method is silent on errors and should behave like that. Callers
should handle throwing of error messages. The reason is that the class
@@ -555,29 +640,29 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et= this;
- if (table->s->fields != EVEX_FIELD_COUNT)
+ if (table->s->fields != Events::FIELD_COUNT)
goto error;
if ((et->dbname.str= get_field(mem_root,
- table->field[EVEX_FIELD_DB])) == NULL)
+ table->field[Events::FIELD_DB])) == NULL)
goto error;
et->dbname.length= strlen(et->dbname.str);
if ((et->name.str= get_field(mem_root,
- table->field[EVEX_FIELD_NAME])) == NULL)
+ table->field[Events::FIELD_NAME])) == NULL)
goto error;
et->name.length= strlen(et->name.str);
if ((et->body.str= get_field(mem_root,
- table->field[EVEX_FIELD_BODY])) == NULL)
+ table->field[Events::FIELD_BODY])) == NULL)
goto error;
et->body.length= strlen(et->body.str);
if ((et->definer.str= get_field(mem_root,
- table->field[EVEX_FIELD_DEFINER])) == NullS)
+ table->field[Events::FIELD_DEFINER])) == NullS)
goto error;
et->definer.length= strlen(et->definer.str);
@@ -594,69 +679,71 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
et->definer_host.length= len;
- et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null();
- res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE);
+ et->starts_null= table->field[Events::FIELD_STARTS]->is_null();
+ res1= table->field[Events::FIELD_STARTS]->
+ get_date(&et->starts,TIME_NO_ZERO_DATE);
- et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null();
- res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
+ et->ends_null= table->field[Events::FIELD_ENDS]->is_null();
+ res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
- if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null())
- et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int();
+ if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null())
+ et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int();
else
et->expression= 0;
/*
If res1 and res2 are true then both fields are empty.
- Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
+ Hence if Events::FIELD_EXECUTE_AT is empty there is an error.
*/
- et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null();
+ et->execute_at_null=
+ table->field[Events::FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
et->execute_at_null));
if (!et->expression &&
- table->field[EVEX_FIELD_EXECUTE_AT]->get_date(&et->execute_at,
- TIME_NO_ZERO_DATE))
+ table->field[Events::FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
+ TIME_NO_ZERO_DATE))
goto error;
/*
In DB the values start from 1 but enum interval_type starts
from 0
*/
- if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null())
- et->interval= (interval_type)
- ((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
+ if (!table->field[Events::FIELD_TRANSIENT_INTERVAL]->is_null())
+ et->interval= (interval_type) ((ulonglong)
+ table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
else
et->interval= (interval_type) 0;
- et->created= table->field[EVEX_FIELD_CREATED]->val_int();
- et->modified= table->field[EVEX_FIELD_MODIFIED]->val_int();
+ et->created= table->field[Events::FIELD_CREATED]->val_int();
+ et->modified= table->field[Events::FIELD_MODIFIED]->val_int();
- table->field[EVEX_FIELD_LAST_EXECUTED]->
+ table->field[Events::FIELD_LAST_EXECUTED]->
get_date(&et->last_executed, TIME_NO_ZERO_DATE);
last_executed_changed= false;
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
- if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
+ if ((ptr= get_field(mem_root, table->field[Events::FIELD_STATUS])) == NullS)
goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
- et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
+ et->status= (ptr[0]=='E'? Event_timed::ENABLED:Event_timed::DISABLED);
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root,
- table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
+ table->field[Events::FIELD_ON_COMPLETION])) == NullS)
goto error;
- et->on_completion= (ptr[0]=='D'? MYSQL_EVENT_ON_COMPLETION_DROP:
- MYSQL_EVENT_ON_COMPLETION_PRESERVE);
+ et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
+ Event_timed::ON_COMPLETION_PRESERVE);
- et->comment.str= get_field(mem_root, table->field[EVEX_FIELD_COMMENT]);
+ et->comment.str= get_field(mem_root, table->field[Events::FIELD_COMMENT]);
if (et->comment.str != NullS)
et->comment.length= strlen(et->comment.str);
else
et->comment.length= 0;
- et->sql_mode= (ulong) table->field[EVEX_FIELD_SQL_MODE]->val_int();
+ et->sql_mode= (ulong) table->field[Events::FIELD_SQL_MODE]->val_int();
DBUG_RETURN(0);
error:
@@ -676,7 +763,7 @@ error:
i_value quantity of time type interval to add
i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
- RETURNS
+ RETURN VALUE
0 OK
1 Error
@@ -834,6 +921,10 @@ done:
SYNOPSIS
Event_timed::compute_next_execution_time()
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+
NOTES
The time is set in execute_at, if no more executions the latter is set to
0000-00-00.
@@ -843,7 +934,6 @@ bool
Event_timed::compute_next_execution_time()
{
TIME time_now;
- my_time_t now;
int tmp;
DBUG_ENTER("Event_timed::compute_next_execution_time");
@@ -852,7 +942,7 @@ Event_timed::compute_next_execution_time()
TIME_to_ulonglong_datetime(&ends),
TIME_to_ulonglong_datetime(&last_executed)));
- if (status == MYSQL_EVENT_DISABLED)
+ if (status == Event_timed::DISABLED)
{
DBUG_PRINT("compute_next_execution_time",
("Event %s is DISABLED", name.str));
@@ -866,14 +956,15 @@ Event_timed::compute_next_execution_time()
{
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
dbname.str, name.str, definer.str));
- dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP);
+ dropped= (on_completion == Event_timed::ON_COMPLETION_DROP);
DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
- status= MYSQL_EVENT_DISABLED;
+ status= Event_timed::DISABLED;
status_changed= true;
}
goto ret;
}
+
my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start());
DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now)));
@@ -885,9 +976,10 @@ Event_timed::compute_next_execution_time()
/* time_now is after ends. don't execute anymore */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
- status= MYSQL_EVENT_DISABLED;
+ DBUG_PRINT("info", ("Dropped=%d", dropped));
+ status= Event_timed::DISABLED;
status_changed= true;
goto ret;
@@ -937,7 +1029,6 @@ Event_timed::compute_next_execution_time()
{
TIME next_exec;
- DBUG_PRINT("info", ("Executed at least once"));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@@ -946,12 +1037,15 @@ Event_timed::compute_next_execution_time()
/* There was previous execution */
if (my_time_compare(&ends, &next_exec) == -1)
{
- DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
+ DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
+ name.str));
/* Next execution after ends. No more executions */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
+ status= Event_timed::DISABLED;
+ status_changed= true;
}
else
{
@@ -1006,7 +1100,6 @@ Event_timed::compute_next_execution_time()
{
TIME next_exec;
- DBUG_PRINT("info", ("Executed at least once."));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@@ -1042,7 +1135,9 @@ Event_timed::compute_next_execution_time()
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ status= Event_timed::DISABLED;
+ status_changed= true;
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
}
else
@@ -1083,9 +1178,6 @@ Event_timed::mark_last_executed(THD *thd)
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
last_executed= time_now; /* was execute_at */
-#ifdef ANDREY_0
- last_executed= execute_at;
-#endif
last_executed_changed= true;
}
@@ -1125,7 +1217,7 @@ Event_timed::drop(THD *thd)
RETURN VALUE
0 OK
- SP_OPEN_TABLE_FAILED Error while opening mysql.event for writing
+ EVEX_OPEN_TABLE_FAILED Error while opening mysql.event for writing
EVEX_WRITE_ROW_FAILED On error to write to disk
others return code from SE in case deletion of the event
@@ -1137,7 +1229,7 @@ Event_timed::update_fields(THD *thd)
{
TABLE *table;
Open_tables_state backup;
- int ret= 0;
+ int ret;
DBUG_ENTER("Event_timed::update_time_fields");
@@ -1145,18 +1237,18 @@ Event_timed::update_fields(THD *thd)
/* No need to update if nothing has changed */
if (!(status_changed || last_executed_changed))
- goto done;
+ DBUG_RETURN(0);
thd->reset_n_backup_open_tables_state(&backup);
- if (evex_open_event_table(thd, TL_WRITE, &table))
+ if (Events::open_event_table(thd, TL_WRITE, &table))
{
- ret= SP_OPEN_TABLE_FAILED;
+ ret= EVEX_OPEN_TABLE_FAILED;
goto done;
}
- if ((ret= evex_db_find_event_by_name(thd, dbname, name, definer, table)))
+ if ((ret= evex_db_find_event_by_name(thd, dbname, name, table)))
goto done;
store_record(table,record[1]);
@@ -1165,15 +1257,15 @@ Event_timed::update_fields(THD *thd)
if (last_executed_changed)
{
- table->field[EVEX_FIELD_LAST_EXECUTED]->set_notnull();
- table->field[EVEX_FIELD_LAST_EXECUTED]->store_time(&last_executed,
- MYSQL_TIMESTAMP_DATETIME);
+ table->field[Events::FIELD_LAST_EXECUTED]->set_notnull();
+ table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed,
+ MYSQL_TIMESTAMP_DATETIME);
last_executed_changed= false;
}
if (status_changed)
{
- table->field[EVEX_FIELD_STATUS]->set_notnull();
- table->field[EVEX_FIELD_STATUS]->store((longlong)status, true);
+ table->field[Events::FIELD_STATUS]->set_notnull();
+ table->field[Events::FIELD_STATUS]->store((longlong)status, true);
status_changed= false;
}
@@ -1215,8 +1307,8 @@ Event_timed::get_create_event(THD *thd, String *buf)
DBUG_ENTER("get_create_event");
DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
- if (expression &&
- event_reconstruct_interval_expression(&expr_buf, interval, expression))
+ if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
+ expression))
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
buf->append(STRING_WITH_LEN("CREATE EVENT "));
@@ -1243,12 +1335,12 @@ Event_timed::get_create_event(THD *thd, String *buf)
buf->append(STRING_WITH_LEN("'"));
}
- if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ if (on_completion == Event_timed::ON_COMPLETION_DROP)
buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
else
buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
- if (status == MYSQL_EVENT_ENABLED)
+ if (status == Event_timed::ENABLED)
buf->append(STRING_WITH_LEN("ENABLE"));
else
buf->append(STRING_WITH_LEN("DISABLE"));
@@ -1273,7 +1365,7 @@ Event_timed::get_create_event(THD *thd, String *buf)
thd THD
mem_root If != NULL use it to compile the event on it
- RETURNS
+ RETURN VALUE
0 success
-99 No rights on this.dbname.str
-100 event in execution (parallel execution is impossible)
@@ -1283,7 +1375,6 @@ Event_timed::get_create_event(THD *thd, String *buf)
int
Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
{
- Security_context *save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
int ret= 0;
@@ -1301,16 +1392,8 @@ Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
running= true;
VOID(pthread_mutex_unlock(&this->LOCK_running));
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
- change_security_context(thd, &security_ctx, &save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
-
if (!sphead && (ret= compile(thd, mem_root)))
goto done;
- /* Now we are sure we have valid this->sphead so we can copy the context */
- sphead->m_security_ctx= security_ctx;
/*
THD::~THD will clean this or if there is DROP DATABASE in the SP then
it will be free there. It should not point to our buffer which is allocated
@@ -1334,12 +1417,11 @@ Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
definer_host.str, dbname.str));
ret= -99;
}
- restore_security_context(thd, save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access, thd->security_ctx->db_access));
VOID(pthread_mutex_lock(&this->LOCK_running));
running= false;
+ /* Will compile every time a new sp_head on different root */
+ free_sp();
VOID(pthread_mutex_unlock(&this->LOCK_running));
done:
@@ -1361,55 +1443,16 @@ done:
/*
- Switches the security context
- Synopsis
- Event_timed::change_security_context()
- thd - thread
- backup - where to store the old context
-
- RETURN
- 0 - OK
- 1 - Error (generates error too)
-*/
-bool
-Event_timed::change_security_context(THD *thd, Security_context *s_ctx,
- Security_context **backup)
-{
- DBUG_ENTER("Event_timed::change_security_context");
- DBUG_PRINT("info",("%s@%s@%s",definer_user.str,definer_host.str, dbname.str));
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- s_ctx->init();
- *backup= 0;
- if (acl_getroot_no_password(s_ctx, definer_user.str, definer_host.str,
- definer_host.str, dbname.str))
- {
- my_error(ER_NO_SUCH_USER, MYF(0), definer_user.str, definer_host.str);
- DBUG_RETURN(true);
- }
- *backup= thd->security_ctx;
- thd->security_ctx= s_ctx;
-#endif
- DBUG_RETURN(false);
-}
-
-
-/*
- Restores the security context
- Synopsis
- Event_timed::restore_security_context()
- thd - thread
- backup - switch to this context
+ Frees the memory of the sp_head object we hold
+ SYNOPSIS
+ Event_timed::free_sp()
*/
void
-Event_timed::restore_security_context(THD *thd, Security_context *backup)
+Event_timed::free_sp()
{
- DBUG_ENTER("Event_timed::restore_security_context");
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (backup)
- thd->security_ctx= backup;
-#endif
- DBUG_VOID_RETURN;
+ delete sphead;
+ sphead= 0;
}
@@ -1445,6 +1488,9 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
CHARSET_INFO *old_character_set_client,
*old_collation_connection,
*old_character_set_results;
+ Security_context *save_ctx;
+ /* this one is local and not needed after exec */
+ Security_context security_ctx;
DBUG_ENTER("Event_timed::compile");
@@ -1488,8 +1534,10 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
thd->query= show_create.c_ptr();
thd->query_length= show_create.length();
- DBUG_PRINT("Event_timed::compile", ("query:%s",thd->query));
+ DBUG_PRINT("info", ("query:%s",thd->query));
+ change_security_context(thd, definer_user, definer_host, dbname,
+ &security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
@@ -1527,6 +1575,7 @@ done:
lex.et->deinit_mutexes();
lex_end(&lex);
+ restore_security_context(thd, save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex;
@@ -1548,72 +1597,63 @@ done:
}
-/*
- Checks whether this thread can lock the object for modification ->
- preventing being spawned for execution, and locks if possible.
- use ::can_spawn_now() only for basic checking because a race
- condition may occur between the check and eventual modification (deletion)
- of the object.
-
- Returns
- true - locked
- false - cannot lock
-*/
-
-my_bool
-Event_timed::can_spawn_now_n_lock(THD *thd)
-{
- my_bool ret= FALSE;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- if (!in_spawned_thread)
- {
- in_spawned_thread= TRUE;
- ret= TRUE;
- locked_by_thread_id= thd->thread_id;
- }
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
-}
-
-
extern pthread_attr_t connection_attrib;
/*
Checks whether is possible and forks a thread. Passes self as argument.
- Returns
- EVENT_EXEC_STARTED - OK
- EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
- EVENT_EXEC_CANT_FORK - Unable to spawn thread (error)
+ RETURN VALUE
+ EVENT_EXEC_STARTED OK
+ EVENT_EXEC_ALREADY_EXEC Thread not forked, already working
+ EVENT_EXEC_CANT_FORK Unable to spawn thread (error)
*/
int
-Event_timed::spawn_now(void * (*thread_func)(void*))
+Event_timed::spawn_now(void * (*thread_func)(void*), void *arg)
{
+ THD *thd= current_thd;
int ret= EVENT_EXEC_STARTED;
- static uint exec_num= 0;
DBUG_ENTER("Event_timed::spawn_now");
- DBUG_PRINT("info", ("this=0x%lx", this));
DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
VOID(pthread_mutex_lock(&this->LOCK_running));
+
+ DBUG_PRINT("info", ("SCHEDULER: execute_at of %s is %lld", name.str,
+ TIME_to_ulonglong_datetime(&execute_at)));
+ mark_last_executed(thd);
+ if (compute_next_execution_time())
+ {
+ sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
+ "Disabling after execution.", dbname.str, name.str);
+ status= DISABLED;
+ }
+ DBUG_PRINT("evex manager", ("[%10s] next exec at [%llu]", name.str,
+ TIME_to_ulonglong_datetime(&execute_at)));
+ /*
+ 1. For one-time event : year is > 0 and expression is 0
+ 2. For recurring, expression is != -=> check execute_at_null in this case
+ */
+ if ((execute_at.year && !expression) || execute_at_null)
+ {
+ sql_print_information("SCHEDULER: [%s.%s of %s] no more executions "
+ "after this one", dbname.str, name.str,
+ definer.str);
+ flags |= EVENT_EXEC_NO_MORE | EVENT_FREE_WHEN_FINISHED;
+ }
+
+ update_fields(thd);
+
if (!in_spawned_thread)
{
pthread_t th;
in_spawned_thread= true;
- if (pthread_create(&th, &connection_attrib, thread_func, (void*)this))
+
+ if (pthread_create(&th, &connection_attrib, thread_func, arg))
{
DBUG_PRINT("info", ("problem while spawning thread"));
ret= EVENT_EXEC_CANT_FORK;
in_spawned_thread= false;
}
-#ifndef DBUG_OFF
- else
- {
- sql_print_information("SCHEDULER: Started thread %d", ++exec_num);
- DBUG_PRINT("info", ("thread spawned"));
- }
-#endif
}
else
{
@@ -1626,55 +1666,207 @@ Event_timed::spawn_now(void * (*thread_func)(void*))
}
-void
+bool
Event_timed::spawn_thread_finish(THD *thd)
{
+ bool should_free;
DBUG_ENTER("Event_timed::spawn_thread_finish");
- VOID(pthread_mutex_lock(&this->LOCK_running));
+ VOID(pthread_mutex_lock(&LOCK_running));
in_spawned_thread= false;
- if ((flags & EVENT_EXEC_NO_MORE) || status == MYSQL_EVENT_DISABLED)
+ DBUG_PRINT("info", ("Sending COND_finished for thread %d", thread_id));
+ thread_id= 0;
+ if (dropped)
+ drop(thd);
+ pthread_cond_broadcast(&COND_finished);
+ should_free= flags & EVENT_FREE_WHEN_FINISHED;
+ VOID(pthread_mutex_unlock(&LOCK_running));
+ DBUG_RETURN(should_free);
+}
+
+
+/*
+ Kills a running event
+ SYNOPSIS
+ Event_timed::kill_thread()
+
+ RETURN VALUE
+ 0 OK
+ -1 EVEX_CANT_KILL
+ !0 Error
+*/
+
+int
+Event_timed::kill_thread(THD *thd)
+{
+ int ret= 0;
+ DBUG_ENTER("Event_timed::kill_thread");
+ pthread_mutex_lock(&LOCK_running);
+ DBUG_PRINT("info", ("thread_id=%lu", thread_id));
+
+ if (thread_id == thd->thread_id)
{
- DBUG_PRINT("info", ("%s exec no more. to drop=%d", name.str, dropped));
- if (dropped)
- drop(thd);
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- delete this;
- DBUG_VOID_RETURN;
+ /*
+ We don't kill ourselves in cases like :
+ alter event e_43 do alter event e_43 do set @a = 4 because
+ we will never receive COND_finished.
+ */
+ DBUG_PRINT("info", ("It's not safe to kill ourselves in self altering queries"));
+ ret= EVEX_CANT_KILL;
}
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- DBUG_VOID_RETURN;
+ else if (thread_id && !(ret= kill_one_thread(thd, thread_id, false)))
+ {
+ thd->enter_cond(&COND_finished, &LOCK_running, "Waiting for finished");
+ DBUG_PRINT("info", ("Waiting for COND_finished from thread %d", thread_id));
+ while (thread_id)
+ pthread_cond_wait(&COND_finished, &LOCK_running);
+
+ DBUG_PRINT("info", ("Got COND_finished"));
+ /* This will implicitly unlock LOCK_running. Hence we return before that */
+ thd->exit_cond("");
+
+ DBUG_RETURN(0);
+ }
+ else if (!thread_id && in_spawned_thread)
+ {
+ /*
+ Because the manager thread waits for the forked thread to update thread_id
+ this situation is impossible.
+ */
+ DBUG_ASSERT(0);
+ }
+ pthread_mutex_unlock(&LOCK_running);
+ DBUG_PRINT("exit", ("%d", ret));
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Checks whether two events have the same name
+
+ SYNOPSIS
+ event_timed_name_equal()
+
+ RETURN VALUE
+ TRUE names are equal
+ FALSE names are not equal
+*/
+
+bool
+event_timed_name_equal(Event_timed *et, LEX_STRING *name)
+{
+ return !sortcmp_lex_string(et->name, *name, system_charset_info);
}
/*
- Unlocks the object after it has been locked with ::can_spawn_now_n_lock()
+ Checks whether two events are in the same schema
+
+ SYNOPSIS
+ event_timed_db_equal()
+
+ RETURN VALUE
+ TRUE schemas are equal
+ FALSE schemas are not equal
+*/
+
+bool
+event_timed_db_equal(Event_timed *et, LEX_STRING *db)
+{
+ return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
+}
+
+
+/*
+ Checks whether two events have the same definer
+
+ SYNOPSIS
+ event_timed_definer_equal()
Returns
- 0 - ok
- 1 - not locked by this thread
+ TRUE definers are equal
+ FALSE definers are not equal
*/
-int
-Event_timed::spawn_unlock(THD *thd)
+bool
+event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
{
- int ret= 0;
- VOID(pthread_mutex_lock(&this->LOCK_running));
- if (!in_spawned_thread)
+ return !sortcmp_lex_string(et->definer, *definer, system_charset_info);
+}
+
+
+/*
+ Checks whether two events are equal by identifiers
+
+ SYNOPSIS
+ event_timed_identifier_equal()
+
+ RETURN VALUE
+ TRUE equal
+ FALSE not equal
+*/
+
+bool
+event_timed_identifier_equal(Event_timed *a, Event_timed *b)
+{
+ return event_timed_name_equal(a, &b->name) &&
+ event_timed_db_equal(a, &b->dbname) &&
+ event_timed_definer_equal(a, &b->definer);
+}
+
+
+/*
+ Switches the security context
+ SYNOPSIS
+ change_security_context()
+ thd Thread
+ user The user
+ host The host of the user
+ db The schema for which the security_ctx will be loaded
+ s_ctx Security context to load state into
+ backup Where to store the old context
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Error (generates error too)
+*/
+
+bool
+change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
+ LEX_STRING db, Security_context *s_ctx,
+ Security_context **backup)
+{
+ DBUG_ENTER("change_security_context");
+ DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ s_ctx->init();
+ *backup= 0;
+ if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
{
- if (locked_by_thread_id == thd->thread_id)
- {
- in_spawned_thread= FALSE;
- locked_by_thread_id= 0;
- }
- else
- {
- sql_print_error("A thread tries to unlock when he hasn't locked. "
- "thread_id=%ld locked by %ld",
- thd->thread_id, locked_by_thread_id);
- DBUG_ASSERT(0);
- ret= 1;
- }
+ my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
+ DBUG_RETURN(TRUE);
}
- VOID(pthread_mutex_unlock(&this->LOCK_running));
- return ret;
+ *backup= thd->security_ctx;
+ thd->security_ctx= s_ctx;
+#endif
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Restores the security context
+ SYNOPSIS
+ restore_security_context()
+ thd - thread
+ backup - switch to this context
+*/
+
+void
+restore_security_context(THD *thd, Security_context *backup)
+{
+ DBUG_ENTER("restore_security_context");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (backup)
+ thd->security_ctx= backup;
+#endif
+ DBUG_VOID_RETURN;
}
diff --git a/sql/field.cc b/sql/field.cc
index 9c504f186b3..1f65adca2d5 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -50,6 +50,9 @@ const char field_separator=',';
#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
((ulong) ((LL(1) << min(arg, 4) * 8) - LL(1)))
+#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table->read_set || bitmap_is_set(table->read_set, field_index))
+#define ASSERT_COLUMN_MARKED_FOR_WRITE DBUG_ASSERT(!table->write_set || bitmap_is_set(table->write_set, field_index))
+
/*
Rules for merging different types of fields in UNION
@@ -1201,9 +1204,11 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length= 21;
longlong value= val_int();
+
if (val_buffer->alloc(length))
return 0;
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
@@ -1218,19 +1223,20 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg)
- :ptr(ptr_arg),null_ptr(null_ptr_arg),
+ :ptr(ptr_arg), null_ptr(null_ptr_arg),
table(0), orig_table(0), table_name(0),
field_name(field_name_arg),
- query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
- unireg_check(unireg_check_arg),
- field_length(length_arg),null_bit(null_bit_arg)
+ key_start(0), part_of_key(0), part_of_key_not_clustered(0),
+ part_of_sortkey(0), unireg_check(unireg_check_arg),
+ field_length(length_arg), null_bit(null_bit_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
comment.str= (char*) "";
comment.length=0;
- fieldnr= 0;
+ field_index= 0;
}
+
uint Field::offset()
{
return (uint) (ptr - (char*) table->record[0]);
@@ -1354,6 +1360,7 @@ longlong Field::convert_decimal2longlong(const my_decimal *val,
int Field_num::store_decimal(const my_decimal *val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
return test(err | store(i, unsigned_flag));
@@ -1378,6 +1385,7 @@ int Field_num::store_decimal(const my_decimal *val)
my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ASSERT(result_type() == INT_RESULT);
longlong nr= val_int();
int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
@@ -1423,6 +1431,7 @@ void Field_num::make_field(Send_field *field)
int Field_str::store_decimal(const my_decimal *d)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
double val;
/* TODO: use decimal2string? */
int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
@@ -1433,6 +1442,7 @@ int Field_str::store_decimal(const my_decimal *d)
my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong nr= val_int();
int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
return decimal_value;
@@ -1498,6 +1508,7 @@ bool Field::get_time(TIME *ltime)
int Field::store_time(TIME *ltime, timestamp_type type)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff);
return store(buff, length, &my_charset_bin);
@@ -1720,6 +1731,7 @@ void Field_decimal::overflow(bool negative)
int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
@@ -2089,6 +2101,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
int Field_decimal::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (unsigned_flag && nr < 0)
{
overflow(1);
@@ -2134,6 +2147,7 @@ int Field_decimal::store(double nr)
int Field_decimal::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[22];
uint length, int_part;
char fyllchar, *to;
@@ -2168,6 +2182,7 @@ int Field_decimal::store(longlong nr, bool unsigned_val)
double Field_decimal::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used,
@@ -2176,6 +2191,7 @@ double Field_decimal::val_real(void)
longlong Field_decimal::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
if (unsigned_flag)
return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
@@ -2189,6 +2205,7 @@ longlong Field_decimal::val_int(void)
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
char *str;
for (str=ptr ; *str == ' ' ; str++) ;
uint tmp_length=(uint) (str-ptr);
@@ -2365,6 +2382,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
DBUG_ENTER("Field_new_decimal::store_value");
#ifndef DBUG_OFF
@@ -2409,6 +2427,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
int Field_new_decimal::store(const char *from, uint length,
CHARSET_INFO *charset)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err;
my_decimal decimal_value;
DBUG_ENTER("Field_new_decimal::store(char*)");
@@ -2456,6 +2475,7 @@ int Field_new_decimal::store(const char *from, uint length,
int Field_new_decimal::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
DBUG_ENTER("Field_new_decimal::store(double)");
@@ -2490,6 +2510,7 @@ int Field_new_decimal::store(double nr)
int Field_new_decimal::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
@@ -2511,12 +2532,14 @@ int Field_new_decimal::store(longlong nr, bool unsigned_val)
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
return store_value(decimal_value);
}
double Field_new_decimal::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double dbl;
my_decimal decimal_value;
my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
@@ -2526,6 +2549,7 @@ double Field_new_decimal::val_real(void)
longlong Field_new_decimal::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong i;
my_decimal decimal_value;
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
@@ -2536,6 +2560,7 @@ longlong Field_new_decimal::val_int(void)
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ENTER("Field_new_decimal::val_decimal");
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
precision, dec);
@@ -2548,6 +2573,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
String *Field_new_decimal::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
my_decimal decimal_value;
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
@@ -2584,6 +2610,7 @@ void Field_new_decimal::sql_type(String &str) const
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int not_used; // We can ignore result from str2int
char *end;
long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
@@ -2630,6 +2657,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_tiny::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -2672,6 +2700,7 @@ int Field_tiny::store(double nr)
int Field_tiny::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -2716,6 +2745,7 @@ int Field_tiny::store(longlong nr, bool unsigned_val)
double Field_tiny::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
(int) ((signed char*) ptr)[0];
return (double) tmp;
@@ -2724,6 +2754,7 @@ double Field_tiny::val_real(void)
longlong Field_tiny::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
(int) ((signed char*) ptr)[0];
return (longlong) tmp;
@@ -2733,6 +2764,7 @@ longlong Field_tiny::val_int(void)
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,5*cs->mbmaxlen);
@@ -2788,6 +2820,7 @@ void Field_tiny::sql_type(String &res) const
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int not_used; // We can ignore result from str2int
char *end;
long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
@@ -2841,6 +2874,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_short::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
nr=rint(nr);
@@ -2892,6 +2926,7 @@ int Field_short::store(double nr)
int Field_short::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
@@ -2946,6 +2981,7 @@ int Field_short::store(longlong nr, bool unsigned_val)
double Field_short::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
short j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -2958,6 +2994,7 @@ double Field_short::val_real(void)
longlong Field_short::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
short j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -2972,6 +3009,7 @@ longlong Field_short::val_int(void)
String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,7*cs->mbmaxlen);
@@ -3062,6 +3100,7 @@ void Field_short::sql_type(String &res) const
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int not_used; // We can ignore result from str2int
char *end;
long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
@@ -3109,6 +3148,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_medium::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -3154,6 +3194,7 @@ int Field_medium::store(double nr)
int Field_medium::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -3202,6 +3243,7 @@ int Field_medium::store(longlong nr, bool unsigned_val)
double Field_medium::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (double) j;
}
@@ -3209,6 +3251,7 @@ double Field_medium::val_real(void)
longlong Field_medium::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (longlong) j;
}
@@ -3217,6 +3260,7 @@ longlong Field_medium::val_int(void)
String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,10*cs->mbmaxlen);
@@ -3234,6 +3278,7 @@ String *Field_medium::val_str(String *val_buffer,
bool Field_medium::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_long(Field_medium::val_int());
}
@@ -3298,6 +3343,7 @@ static bool test_if_minus(CHARSET_INFO *cs,
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
ulong tmp_scan;
longlong tmp;
long store_tmp;
@@ -3370,6 +3416,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_long::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
nr=rint(nr);
@@ -3421,6 +3468,7 @@ int Field_long::store(double nr)
int Field_long::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
DBUG_ASSERT(table->in_use == current_thd); // General safety
@@ -3474,6 +3522,7 @@ int Field_long::store(longlong nr, bool unsigned_val)
double Field_long::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3486,6 +3535,7 @@ double Field_long::val_real(void)
longlong Field_long::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
/* See the comment in Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
@@ -3501,6 +3551,7 @@ longlong Field_long::val_int(void)
String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,12*cs->mbmaxlen);
@@ -3527,6 +3578,7 @@ String *Field_long::val_str(String *val_buffer,
bool Field_long::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_long(Field_long::val_int());
}
@@ -3591,6 +3643,7 @@ void Field_long::sql_type(String &res) const
int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
longlong tmp;
int error= 0;
char *end;
@@ -3632,6 +3685,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_longlong::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
longlong res;
@@ -3683,6 +3737,7 @@ int Field_longlong::store(double nr)
int Field_longlong::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (nr < 0) // Only possible error
@@ -3713,6 +3768,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val)
double Field_longlong::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3734,6 +3790,7 @@ double Field_longlong::val_real(void)
longlong Field_longlong::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3772,6 +3829,7 @@ String *Field_longlong::val_str(String *val_buffer,
bool Field_longlong::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag);
}
@@ -3864,6 +3922,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_float::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
float j;
int error= 0;
@@ -3928,12 +3987,14 @@ int Field_float::store(double nr)
int Field_float::store(longlong nr, bool unsigned_val)
{
- return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
+ return Field_float::store(unsigned_val ? ulonglong2double((ulonglong) nr) :
+ (double) nr);
}
double Field_float::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
float j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3964,6 +4025,7 @@ longlong Field_float::val_int(void)
String *Field_float::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
float nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4109,6 +4171,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
bool Field_float::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store((float) Field_float::val_real(), dec, (String*) 0);
}
@@ -4152,6 +4215,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_double::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (isnan(nr))
@@ -4209,7 +4273,8 @@ int Field_double::store(double nr)
int Field_double::store(longlong nr, bool unsigned_val)
{
- return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
+ return Field_double::store(unsigned_val ? ulonglong2double((ulonglong) nr) :
+ (double) nr);
}
@@ -4222,6 +4287,7 @@ int Field_real::store_decimal(const my_decimal *dm)
double Field_double::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4236,6 +4302,7 @@ double Field_double::val_real(void)
longlong Field_double::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double j;
longlong res;
#ifdef WORDS_BIGENDIAN
@@ -4275,6 +4342,7 @@ warn:
my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value);
return decimal_value;
}
@@ -4283,6 +4351,7 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4371,6 +4440,7 @@ bool Field_double::send_binary(Protocol *protocol)
int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double a,b;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4529,6 +4599,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME l_time;
my_time_t tmp= 0;
int error;
@@ -4599,6 +4670,7 @@ int Field_timestamp::store(double nr)
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME l_time;
my_time_t timestamp= 0;
int error;
@@ -4650,11 +4722,13 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
double Field_timestamp::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (double) Field_timestamp::val_int();
}
longlong Field_timestamp::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp;
TIME time_tmp;
THD *thd= table->in_use;
@@ -4680,6 +4754,7 @@ longlong Field_timestamp::val_int(void)
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp, temp2;
TIME time_tmp;
THD *thd= table->in_use;
@@ -4909,6 +4984,7 @@ int Field_time::store_time(TIME *ltime, timestamp_type type)
int Field_time::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (nr > 8385959.0)
@@ -4946,6 +5022,7 @@ int Field_time::store(double nr)
int Field_time::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (nr < (longlong) -8385959L && !unsigned_val)
@@ -4983,12 +5060,14 @@ int Field_time::store(longlong nr, bool unsigned_val)
double Field_time::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 j= (uint32) uint3korr(ptr);
return (double) j;
}
longlong Field_time::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (longlong) sint3korr(ptr);
}
@@ -5001,6 +5080,7 @@ longlong Field_time::val_int(void)
String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
TIME ltime;
val_buffer->alloc(19);
long tmp=(long) sint3korr(ptr);
@@ -5110,6 +5190,7 @@ void Field_time::sql_type(String &res) const
int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char *end;
int error;
long nr= my_strntol(cs, from, len, 10, &end, &error);
@@ -5148,6 +5229,7 @@ int Field_year::store(double nr)
int Field_year::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr= 0;
@@ -5168,6 +5250,7 @@ int Field_year::store(longlong nr, bool unsigned_val)
bool Field_year::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong tmp= Field_year::val_int();
return protocol->store_short(tmp);
}
@@ -5181,6 +5264,7 @@ double Field_year::val_real(void)
longlong Field_year::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int tmp= (int) ((uchar*) ptr)[0];
if (field_length != 4)
tmp%=100; // Return last 2 char
@@ -5218,6 +5302,7 @@ void Field_year::sql_type(String &res) const
int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME l_time;
uint32 tmp;
int error;
@@ -5273,6 +5358,7 @@ int Field_date::store(double nr)
int Field_date::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME not_used;
int error;
longlong initial_nr= nr;
@@ -5323,6 +5409,7 @@ bool Field_date::send_binary(Protocol *protocol)
double Field_date::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -5336,6 +5423,7 @@ double Field_date::val_real(void)
longlong Field_date::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -5350,6 +5438,7 @@ longlong Field_date::val_int(void)
String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
TIME ltime;
val_buffer->alloc(field_length);
int32 tmp;
@@ -5421,6 +5510,7 @@ void Field_date::sql_type(String &res) const
int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME l_time;
long tmp;
int error;
@@ -5461,6 +5551,7 @@ int Field_newdate::store(double nr)
int Field_newdate::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME l_time;
longlong tmp;
int error;
@@ -5489,6 +5580,7 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
int Field_newdate::store_time(TIME *ltime,timestamp_type type)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
@@ -5514,12 +5606,14 @@ bool Field_newdate::send_binary(Protocol *protocol)
double Field_newdate::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (double) Field_newdate::val_int();
}
longlong Field_newdate::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulong j= uint3korr(ptr);
j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
return (longlong) j;
@@ -5529,6 +5623,7 @@ longlong Field_newdate::val_int(void)
String *Field_newdate::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
val_buffer->alloc(field_length);
val_buffer->length(field_length);
uint32 tmp=(uint32) uint3korr(ptr);
@@ -5605,6 +5700,7 @@ void Field_newdate::sql_type(String &res) const
int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME time_tmp;
int error;
ulonglong tmp= 0;
@@ -5656,6 +5752,7 @@ int Field_datetime::store(double nr)
int Field_datetime::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
TIME not_used;
int error;
longlong initial_nr= nr;
@@ -5692,6 +5789,7 @@ int Field_datetime::store(longlong nr, bool unsigned_val)
int Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
longlong tmp;
int error= 0;
/*
@@ -5733,6 +5831,7 @@ double Field_datetime::val_real(void)
longlong Field_datetime::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -5747,6 +5846,7 @@ longlong Field_datetime::val_int(void)
String *Field_datetime::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
val_buffer->alloc(field_length);
val_buffer->length(field_length);
ulonglong tmp;
@@ -5878,6 +5978,7 @@ void Field_datetime::sql_type(String &res) const
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0, well_formed_error;
uint32 not_used;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -5954,6 +6055,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
int Field_str::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint length;
bool use_scientific_notation= TRUE;
@@ -6029,6 +6131,7 @@ int Field_longstr::store_decimal(const my_decimal *d)
double Field_string::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
CHARSET_INFO *cs= charset();
@@ -6038,6 +6141,7 @@ double Field_string::val_real(void)
longlong Field_string::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
CHARSET_INFO *cs=charset();
@@ -6048,6 +6152,7 @@ longlong Field_string::val_int(void)
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
@@ -6058,6 +6163,7 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
decimal_value);
return decimal_value;
@@ -6295,6 +6401,7 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table)
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint32 not_used, copy_length;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
@@ -6369,6 +6476,7 @@ int Field_varstring::store(longlong nr, bool unsigned_val)
double Field_varstring::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
@@ -6379,6 +6487,7 @@ double Field_varstring::val_real(void)
longlong Field_varstring::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
@@ -6389,6 +6498,7 @@ longlong Field_varstring::val_int(void)
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
val_ptr->set((const char*) ptr+length_bytes, length, field_charset);
return val_ptr;
@@ -6397,6 +6507,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
str2my_decimal(E_DEC_FATAL_ERROR, ptr+length_bytes, length, charset(),
decimal_value);
@@ -6937,6 +7048,7 @@ void Field_blob::put_length(char *pos, uint32 length)
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0, well_formed_error;
if (!length)
{
@@ -7023,6 +7135,7 @@ int Field_blob::store(longlong nr, bool unsigned_val)
double Field_blob::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used, *blob;
uint32 length;
@@ -7039,6 +7152,7 @@ double Field_blob::val_real(void)
longlong Field_blob::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
@@ -7051,6 +7165,7 @@ longlong Field_blob::val_int(void)
String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
@@ -7063,6 +7178,7 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
const char *blob;
memcpy_fixed(&blob, ptr+packlength, sizeof(const char*));
if (!blob)
@@ -7631,6 +7747,7 @@ void Field_enum::store_type(ulonglong value)
int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
uint32 not_used;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -7677,6 +7794,7 @@ int Field_enum::store(double nr)
int Field_enum::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if ((ulonglong) nr > typelib->count || nr == 0)
{
@@ -7697,44 +7815,45 @@ double Field_enum::val_real(void)
longlong Field_enum::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
switch (packlength) {
case 1:
return (longlong) (uchar) ptr[0];
case 2:
- {
- uint16 tmp;
+ {
+ uint16 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint2korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=sint2korr(ptr);
+ else
#endif
- shortget(tmp,ptr);
- return (longlong) tmp;
- }
+ shortget(tmp,ptr);
+ return (longlong) tmp;
+ }
case 3:
return (longlong) uint3korr(ptr);
case 4:
- {
- uint32 tmp;
+ {
+ uint32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=uint4korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=uint4korr(ptr);
+ else
#endif
- longget(tmp,ptr);
- return (longlong) tmp;
- }
+ longget(tmp,ptr);
+ return (longlong) tmp;
+ }
case 8:
- {
- longlong tmp;
+ {
+ longlong tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=sint8korr(ptr);
+ else
#endif
- longlongget(tmp,ptr);
- return tmp;
- }
+ longlongget(tmp,ptr);
+ return tmp;
+ }
}
return 0; // impossible
}
@@ -7812,6 +7931,7 @@ void Field_enum::sql_type(String &res) const
int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
bool got_warning= 0;
int err= 0;
char *not_used;
@@ -7851,6 +7971,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
int Field_set::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
(longlong) 1))
@@ -8034,6 +8155,7 @@ Field *Field_bit::new_key_field(MEM_ROOT *root,
int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
for (; length && !*from; from++, length--); // skip left 0's
@@ -8080,7 +8202,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
int Field_bit::store(double nr)
{
- return store((longlong) nr, FALSE);
+ return Field_bit::store((longlong) nr, FALSE);
}
@@ -8109,6 +8231,7 @@ double Field_bit::val_real(void)
longlong Field_bit::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong bits= 0;
if (bit_len)
{
@@ -8133,6 +8256,7 @@ longlong Field_bit::val_int(void)
String *Field_bit::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
char buff[sizeof(longlong)];
uint length= min(pack_length(), sizeof(longlong));
ulonglong bits= val_int();
@@ -8148,6 +8272,7 @@ String *Field_bit::val_str(String *val_buffer,
my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value);
return deciaml_value;
}
@@ -8277,6 +8402,7 @@ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
uchar bits= field_length & 7;
@@ -8839,15 +8965,14 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
null_bit= ((uchar) 1) << null_bit;
}
- switch (field_type)
- {
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_TIMESTAMP:
- field_charset= &my_charset_bin;
- default: break;
+ switch (field_type) {
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_NEWDATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_TIMESTAMP:
+ field_charset= &my_charset_bin;
+ default: break;
}
if (f_is_alpha(pack_flag))
@@ -9059,14 +9184,15 @@ create_field::create_field(Field *old_field,Field *orig_field)
diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
orig_field->table->record[0]);
orig_field->move_field_offset(diff); // Points now at default_values
- is_null= orig_field->is_real_null();
- res= orig_field->val_str(&tmp);
- orig_field->move_field_offset(-diff); // Back to record[0]
- if (!is_null)
+ if (!orig_field->is_real_null())
{
+ char buff[MAX_FIELD_WIDTH], *pos;
+ String tmp(buff, sizeof(buff), charset), *res;
+ res= orig_field->val_str(&tmp);
pos= (char*) sql_strmake(res->ptr(), res->length());
def= new Item_string(pos, res->length(), charset);
}
+ orig_field->move_field_offset(-diff); // Back to record[0]
}
}
diff --git a/sql/field.h b/sql/field.h
index b473100eaab..2ac7ec2c69d 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -62,10 +62,9 @@ public:
struct st_table *orig_table; // Pointer to original table
const char **table_name, *field_name;
LEX_STRING comment;
- query_id_t query_id; // For quick test of used fields
- bool add_index; // For check if field will be indexed
/* Field is part of the following keys */
- key_map key_start,part_of_key,part_of_sortkey;
+ key_map key_start, part_of_key, part_of_key_not_clustered;
+ key_map part_of_sortkey;
/*
We use three additional unireg types for TIMESTAMP to overcome limitation
of current binary format of .frm file. We'd like to be able to support
@@ -88,12 +87,8 @@ public:
utype unireg_check;
uint32 field_length; // Length of field
- uint field_index; // field number in fields array
uint32 flags;
- /* fieldnr is the id of the field (first field = 1) as is also
- used in key_part.
- */
- uint16 fieldnr;
+ uint16 field_index; // field number in fields array
uchar null_bit; // Bit used to test null bit
Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 42d25dbbaee..4e48df5db9f 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -44,6 +44,7 @@ static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos);
+static void register_used_fields(SORTPARAM *param);
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek,
uint maxbuffer,IO_CACHE *tempfile,
@@ -66,11 +67,11 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
table Table to sort
sortorder How to sort the table
s_length Number of elements in sortorder
- select condition to apply to the rows
- special Not used.
- (This could be used to sort the rows pointed on by
- select->file)
- examined_rows Store number of examined rows here
+ select Condition to apply to the rows
+ ha_maxrows Return only this many rows
+ sort_positions Set to 1 if we want to force sorting by position
+ (Needed by UPDATE/INSERT or ALTER TABLE)
+ examined_rows Store number of examined rows here
IMPLEMENTATION
Creates a set of pointers that can be used to read the rows
@@ -81,6 +82,10 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
Before calling filesort, one must have done
table->file->info(HA_STATUS_VARIABLE)
+ NOTES
+ If we sort by position (like if sort_positions is 1) filesort() will
+ call table->prepare_for_position().
+
RETURN
HA_POS_ERROR Error
# Number of rows
@@ -92,7 +97,8 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
*/
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
- SQL_SELECT *select, ha_rows max_rows, ha_rows *examined_rows)
+ SQL_SELECT *select, ha_rows max_rows,
+ bool sort_positions, ha_rows *examined_rows)
{
int error;
ulong memavl, min_sort_memory;
@@ -128,8 +134,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.ref_length= table->file->ref_length;
param.addon_field= 0;
param.addon_length= 0;
- if (!(table->file->table_flags() & HA_FAST_KEY_READ) &&
- !table->fulltext_searched)
+ if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
+ !table->fulltext_searched && !sort_positions)
{
/*
Get the descriptors of all fields whose values are appended
@@ -175,7 +181,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick && select->quick->records > 0L)
{
records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
- table->file->records)+EXTRA_RECORDS;
+ table->file->stats.records)+EXTRA_RECORDS;
selected_records_file=0;
}
else
@@ -404,8 +410,11 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
TABLE *sort_form;
volatile THD::killed_state *killed= &current_thd->killed;
handler *file;
+ MY_BITMAP *save_read_set, *save_write_set;
DBUG_ENTER("find_all_keys");
- DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
+ DBUG_PRINT("info",("using: %s",
+ (select ? select->quick ? "ranges" : "where":
+ "every row")));
idx=indexpos=0;
error=quick_select=0;
@@ -415,7 +424,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->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];
@@ -437,6 +446,19 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
select, 1, 1);
}
+ /* Remember original bitmaps */
+ save_read_set= sort_form->read_set;
+ save_write_set= sort_form->write_set;
+ /* Set up temporary column read map for columns used by sort */
+ bitmap_clear_all(&sort_form->tmp_set);
+ /* Temporary set for register_used_fields and register_field_in_read_map */
+ sort_form->read_set= &sort_form->tmp_set;
+ register_used_fields(param);
+ if (select && select->cond)
+ select->cond->walk(&Item::register_field_in_read_map, 1,
+ (byte*) sort_form);
+ sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
+
for (;;)
{
if (quick_select)
@@ -515,6 +537,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->ha_rnd_end();
}
+ /* Signal we should use orignal column read and write maps */
+ sort_form->column_bitmaps_set(save_read_set, save_write_set);
+
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
@@ -845,6 +870,50 @@ static void make_sortkey(register SORTPARAM *param,
return;
}
+
+/*
+ Register fields used by sorting in the sorted table's read set
+*/
+
+static void register_used_fields(SORTPARAM *param)
+{
+ reg1 SORT_FIELD *sort_field;
+ reg5 uint length;
+ TABLE *table=param->sort_form;
+ MY_BITMAP *bitmap= table->read_set;
+
+ for (sort_field= param->local_sortorder ;
+ sort_field != param->end ;
+ sort_field++)
+ {
+ Field *field;
+ if ((field= sort_field->field))
+ {
+ if (field->table == table)
+ bitmap_set_bit(bitmap, field->field_index);
+ }
+ else
+ { // Item
+ sort_field->item->walk(&Item::register_field_in_read_map, 1,
+ (byte *) table);
+ }
+ }
+
+ if (param->addon_field)
+ {
+ SORT_ADDON_FIELD *addonf= param->addon_field;
+ Field *field;
+ for ( ; (field= addonf->field) ; addonf++)
+ bitmap_set_bit(bitmap, field->field_index);
+ }
+ else
+ {
+ /* Save filepos last */
+ table->prepare_for_position();
+ }
+}
+
+
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
FILESORT_INFO *table_sort)
{
@@ -1353,7 +1422,8 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
uint length= 0;
uint fields= 0;
uint null_fields= 0;
- query_id_t query_id= thd->query_id;
+ MY_BITMAP *read_set= (*ptabfield)->table->read_set;
+
/*
If there is a reference to a field in the query add it
to the the set of appended fields.
@@ -1365,17 +1435,9 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
*/
*plength= 0;
- /*
- The following statement is added to avoid sorting in alter_table.
- The fact is the filter 'field->query_id != thd->query_id'
- doesn't work for alter table
- */
- if (thd->lex->sql_command != SQLCOM_SELECT &&
- thd->lex->sql_command != SQLCOM_INSERT_SELECT)
- return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
- if (field->query_id != query_id)
+ if (!bitmap_is_set(read_set, field->field_index))
continue;
if (field->flags & BLOB_FLAG)
return 0;
@@ -1398,7 +1460,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
null_fields= 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
- if (field->query_id != thd->query_id)
+ if (!bitmap_is_set(read_set, field->field_index))
continue;
addonf->field= field;
addonf->offset= length;
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 473fb149871..d8159a81f90 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -25,7 +25,8 @@
We will need an updated Berkeley DB version for this.
- Killing threads that has got a 'deadlock'
- SHOW TABLE STATUS should give more information about the table.
- - Get a more accurate count of the number of rows (estimate_rows_upper_bound()).
+ - Get a more accurate count of the number of rows
+ (estimate_rows_upper_bound()).
We could store the found number of rows when the table is scanned and
then increment the counter for each attempted write.
- We will need to extend the manager thread to makes checkpoints at
@@ -97,6 +98,9 @@ pthread_mutex_t bdb_mutex;
static DB_ENV *db_env;
static HASH bdb_open_tables;
+static const char berkeley_hton_name[]= "BerkeleyDB";
+static const int berkeley_hton_name_length=sizeof(berkeley_hton_name)-1;
+
const char *berkeley_lock_names[] =
{ "DEFAULT", "OLDEST", "RANDOM", "YOUNGEST", "EXPIRE", "MAXLOCKS",
"MAXWRITE", "MINLOCKS", "MINWRITE", 0 };
@@ -123,53 +127,14 @@ static int berkeley_rollback(THD *thd, bool all);
static int berkeley_rollback_to_savepoint(THD* thd, void *savepoint);
static int berkeley_savepoint(THD* thd, void *savepoint);
static int berkeley_release_savepoint(THD* thd, void *savepoint);
-static handler *berkeley_create_handler(TABLE_SHARE *table);
-
-static const char berkeley_hton_name[]= "BerkeleyDB";
-static const char berkeley_hton_comment[]=
- "Supports transactions and page-level locking";
+static handler *berkeley_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
-handlerton berkeley_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- berkeley_hton_name,
- SHOW_OPTION_YES,
- berkeley_hton_comment,
- DB_TYPE_BERKELEY_DB,
- berkeley_init,
- 0, /* slot */
- sizeof(DB_TXN *), /* savepoint size */
- berkeley_close_connection,
- berkeley_savepoint, /* savepoint_set */
- berkeley_rollback_to_savepoint, /* savepoint_rollback */
- berkeley_release_savepoint, /* savepoint_release */
- berkeley_commit,
- berkeley_rollback,
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- berkeley_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- berkeley_end, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- berkeley_flush_logs, /* Flush logs */
- berkeley_show_status, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill Files Table */
- HTON_CLOSE_CURSORS_AT_COMMIT | HTON_FLUSH_AFTER_RENAME,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
+handlerton berkeley_hton;
-handler *berkeley_create_handler(TABLE_SHARE *table)
+static handler *berkeley_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_berkeley(table);
+ return new (mem_root) ha_berkeley(table);
}
typedef struct st_berkeley_trx_data {
@@ -181,12 +146,27 @@ typedef struct st_berkeley_trx_data {
/* General functions */
-bool berkeley_init(void)
+int berkeley_init(void)
{
DBUG_ENTER("berkeley_init");
+ berkeley_hton.state=SHOW_OPTION_YES;
+ berkeley_hton.db_type=DB_TYPE_BERKELEY_DB;
+ berkeley_hton.savepoint_offset=sizeof(DB_TXN *);
+ berkeley_hton.close_connection=berkeley_close_connection;
+ berkeley_hton.savepoint_set=berkeley_savepoint;
+ berkeley_hton.savepoint_rollback=berkeley_rollback_to_savepoint;
+ berkeley_hton.savepoint_release=berkeley_release_savepoint;
+ berkeley_hton.commit=berkeley_commit;
+ berkeley_hton.rollback=berkeley_rollback;
+ berkeley_hton.create=berkeley_create_handler;
+ berkeley_hton.panic=berkeley_end;
+ berkeley_hton.flush_logs=berkeley_flush_logs;
+ berkeley_hton.show_status=berkeley_show_status;
+ berkeley_hton.flags=HTON_CLOSE_CURSORS_AT_COMMIT | HTON_FLUSH_AFTER_RENAME;
+
if (have_berkeley_db != SHOW_OPTION_YES)
- goto error;
+ return 0; // nothing else to do
if (!berkeley_tmpdir)
berkeley_tmpdir=mysql_tmpdir;
@@ -373,7 +353,6 @@ static int berkeley_release_savepoint(THD* thd, void *savepoint)
static bool berkeley_show_logs(THD *thd, stat_print_fn *stat_print)
{
char **all_logs, **free_logs, **a, **f;
- uint hton_name_len= strlen(berkeley_hton.name);
int error=1;
MEM_ROOT **root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,THR_MALLOC);
MEM_ROOT show_logs_root, *old_mem_root= *root_ptr;
@@ -382,6 +361,7 @@ static bool berkeley_show_logs(THD *thd, stat_print_fn *stat_print)
init_sql_alloc(&show_logs_root, BDB_LOG_ALLOC_BLOCK_SIZE,
BDB_LOG_ALLOC_BLOCK_SIZE);
*root_ptr= &show_logs_root;
+ all_logs= free_logs= 0;
if ((error= db_env->log_archive(db_env, &all_logs,
DB_ARCH_ABS | DB_ARCH_LOG)) ||
@@ -401,21 +381,25 @@ static bool berkeley_show_logs(THD *thd, stat_print_fn *stat_print)
if (f && *f && strcmp(*a, *f) == 0)
{
f++;
- if ((error= stat_print(thd, berkeley_hton.name, hton_name_len,
- *a, strlen(*a),
+ if ((error= stat_print(thd, berkeley_hton_name,
+ berkeley_hton_name_length, *a, strlen(*a),
STRING_WITH_LEN(SHOW_LOG_STATUS_FREE))))
break;
}
else
{
- if ((error= stat_print(thd, berkeley_hton.name, hton_name_len,
- *a, strlen(*a),
+ if ((error= stat_print(thd, berkeley_hton_name,
+ berkeley_hton_name_length, *a, strlen(*a),
STRING_WITH_LEN(SHOW_LOG_STATUS_INUSE))))
break;
}
}
}
err:
+ if (all_logs)
+ free(all_logs);
+ if (free_logs)
+ free(free_logs);
free_root(&show_logs_root,MYF(0));
*root_ptr= old_mem_root;
DBUG_RETURN(error);
@@ -479,7 +463,7 @@ void berkeley_cleanup_log_files(void)
ha_berkeley::ha_berkeley(TABLE_SHARE *table_arg)
:handler(&berkeley_hton, table_arg), alloc_ptr(0), rec_buff(0), file(0),
int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
- HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
+ HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS |
HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
HA_CAN_GEOMETRY |
HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
@@ -783,7 +767,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
transaction=0;
cursor=0;
key_read=0;
- block_size=8192; // Berkeley DB block size
+ stats.block_size=8192; // Berkeley DB block size
share->fixed_length_row= !(table_share->db_create_options &
HA_OPTION_PACK_RECORD);
@@ -799,7 +783,7 @@ int ha_berkeley::close(void)
my_free((char*) rec_buff,MYF(MY_ALLOW_ZERO_PTR));
my_free(alloc_ptr,MYF(MY_ALLOW_ZERO_PTR));
- ha_berkeley::extra(HA_EXTRA_RESET); // current_row buffer
+ ha_berkeley::reset(); // current_row buffer
DBUG_RETURN(free_share(share,table, hidden_primary_key,0));
}
@@ -900,11 +884,13 @@ void ha_berkeley::unpack_row(char *record, DBT *row)
else
{
/* Copy null bits */
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
const char *ptr= (const char*) row->data;
memcpy(record, ptr, table_share->null_bytes);
ptr+= table_share->null_bytes;
for (Field **field=table->field ; *field ; field++)
ptr= (*field)->unpack(record + (*field)->offset(), ptr);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
}
}
@@ -962,6 +948,7 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
KEY *key_info=table->key_info+keynr;
KEY_PART_INFO *key_part=key_info->key_part;
KEY_PART_INFO *end=key_part+key_info->key_parts;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
DBUG_ENTER("create_key");
key->data=buff;
@@ -985,6 +972,7 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
}
key->size= (buff - (char*) key->data);
DBUG_DUMP("key",(char*) key->data, key->size);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
DBUG_RETURN(key);
}
@@ -1002,6 +990,7 @@ DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
KEY *key_info=table->key_info+keynr;
KEY_PART_INFO *key_part=key_info->key_part;
KEY_PART_INFO *end=key_part+key_info->key_parts;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
DBUG_ENTER("bdb:pack_key");
bzero((char*) key,sizeof(*key));
@@ -1029,6 +1018,7 @@ DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
}
key->size= (buff - (char*) key->data);
DBUG_DUMP("key",(char*) key->data, key->size);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
DBUG_RETURN(key);
}
@@ -1267,8 +1257,8 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DB_TXN *sub_trans;
bool primary_key_changed;
DBUG_ENTER("update_row");
- LINT_INIT(error);
+ LINT_INIT(error);
statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
@@ -1849,8 +1839,9 @@ void ha_berkeley::info(uint flag)
DBUG_ENTER("ha_berkeley::info");
if (flag & HA_STATUS_VARIABLE)
{
- records = share->rows + changed_rows; // Just to get optimisations right
- deleted = 0;
+ // Just to get optimizations right
+ stats.records = share->rows + changed_rows;
+ stats.deleted = 0;
}
if ((flag & HA_STATUS_CONST) || version != share->version)
{
@@ -1871,19 +1862,8 @@ void ha_berkeley::info(uint flag)
int ha_berkeley::extra(enum ha_extra_function operation)
{
switch (operation) {
- case HA_EXTRA_RESET:
case HA_EXTRA_RESET_STATE:
- key_read=0;
- using_ignore=0;
- if (current_row.flags & (DB_DBT_MALLOC | DB_DBT_REALLOC))
- {
- current_row.flags=0;
- if (current_row.data)
- {
- free(current_row.data);
- current_row.data=0;
- }
- }
+ reset();
break;
case HA_EXTRA_KEYREAD:
key_read=1; // Query satisfied with key
@@ -1906,8 +1886,17 @@ int ha_berkeley::extra(enum ha_extra_function operation)
int ha_berkeley::reset(void)
{
- ha_berkeley::extra(HA_EXTRA_RESET);
- key_read=0; // Reset to state after open
+ key_read= 0;
+ using_ignore= 0;
+ if (current_row.flags & (DB_DBT_MALLOC | DB_DBT_REALLOC))
+ {
+ current_row.flags= 0;
+ if (current_row.data)
+ {
+ free(current_row.data);
+ current_row.data= 0;
+ }
+ }
return 0;
}
@@ -2196,7 +2185,7 @@ int ha_berkeley::rename_table(const char * from, const char * to)
double ha_berkeley::scan_time()
{
- return rows2double(records/3);
+ return rows2double(stats.records/3);
}
ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
@@ -2249,14 +2238,18 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
end_pos=end_range.less;
else
end_pos=end_range.less+end_range.equal;
- rows=(end_pos-start_pos)*records;
+ rows=(end_pos-start_pos)*stats.records;
DBUG_PRINT("exit",("rows: %g",rows));
DBUG_RETURN((ha_rows)(rows <= 1.0 ? 1 : rows));
}
-ulonglong ha_berkeley::get_auto_increment()
+void ha_berkeley::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
+ /* Ideally in case of real error (not "empty table") nr should be ~ULL(0) */
ulonglong nr=1; // Default if error or new key
int error;
(void) ha_berkeley::extra(HA_EXTRA_KEYREAD);
@@ -2267,9 +2260,18 @@ ulonglong ha_berkeley::get_auto_increment()
if (!table_share->next_number_key_offset)
{ // Autoincrement at key-start
error=ha_berkeley::index_last(table->record[1]);
+ /* has taken read lock on page of max key so reserves to infinite */
+ *nb_reserved_values= ULONGLONG_MAX;
}
else
{
+ /*
+ 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;
DBT row,old_key;
bzero((char*) &row,sizeof(row));
KEY *key_info= &table->key_info[active_index];
@@ -2310,7 +2312,7 @@ ulonglong ha_berkeley::get_auto_increment()
table->next_number_field->val_int_offset(table_share->rec_buff_length)+1;
ha_berkeley::index_end();
(void) ha_berkeley::extra(HA_EXTRA_NO_KEYREAD);
- return nr;
+ *first_value= nr;
}
void ha_berkeley::print_error(int error, myf errflag)
@@ -2732,15 +2734,17 @@ bool ha_berkeley::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
+struct st_mysql_storage_engine berkeley_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &berkeley_hton };
mysql_declare_plugin(berkeley)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &berkeley_hton,
+ &berkeley_storage_engine,
berkeley_hton_name,
"Sleepycat Software",
- berkeley_hton_comment,
- NULL, /* Plugin Init */
+ "Supports transactions and page-level locking",
+ berkeley_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100, /* 1.0 */
0
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 21b618b8d6d..47aab1fbb68 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -90,7 +90,7 @@ class ha_berkeley: public handler
ulong index_flags(uint idx, uint part, bool all_parts) const;
const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
- ulong table_flags(void) const { return int_table_flags; }
+ ulonglong table_flags(void) const { return int_table_flags; }
uint max_supported_keys() const { return MAX_KEY-1; }
uint extra_rec_buf_length() const { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_rows_upper_bound();
@@ -98,7 +98,6 @@ class ha_berkeley: public handler
uint max_supported_key_part_length() const { return UINT_MAX32; }
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
- bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -149,7 +148,10 @@ class ha_berkeley: public handler
int5store(to,share->auto_ident);
pthread_mutex_unlock(&share->mutex);
}
- ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
void print_error(int error, myf errflag);
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
bool primary_key_is_clustered() { return true; }
@@ -172,7 +174,7 @@ extern char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
extern long berkeley_lock_scan_time;
extern TYPELIB berkeley_lock_typelib;
-bool berkeley_init(void);
+int berkeley_init(void);
int berkeley_end(ha_panic_function type);
bool berkeley_flush_logs(void);
bool berkeley_show_status(THD *thd, stat_print_fn *print, enum ha_stat_type);
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index f4fc5f47193..91111a433dc 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -364,57 +364,19 @@ pthread_mutex_t federated_mutex; // To init the hash
static int federated_init= FALSE; // Checking the state of hash
/* Static declaration for handerton */
-static handler *federated_create_handler(TABLE_SHARE *table);
+static handler *federated_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
static int federated_commit(THD *thd, bool all);
static int federated_rollback(THD *thd, bool all);
/* Federated storage engine handlerton */
-static const char federated_hton_name[]= "FEDERATED";
-static const char federated_hton_comment[]= "Federated MySQL storage engine";
-
-handlerton federated_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- federated_hton_name,
- SHOW_OPTION_YES,
- federated_hton_comment,
- DB_TYPE_FEDERATED_DB,
- federated_db_init,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- federated_commit, /* commit */
- federated_rollback, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- federated_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- federated_db_end, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill FILES table */
- HTON_ALTER_NOT_SUPPORTED,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
-
-
-static handler *federated_create_handler(TABLE_SHARE *table)
+handlerton federated_hton;
+
+static handler *federated_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
{
- return new ha_federated(table);
+ return new (mem_root) ha_federated(table);
}
@@ -439,9 +401,18 @@ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
TRUE Error
*/
-bool federated_db_init()
+int federated_db_init()
{
DBUG_ENTER("federated_db_init");
+
+ federated_hton.state= SHOW_OPTION_YES;
+ federated_hton.db_type= DB_TYPE_FEDERATED_DB;
+ federated_hton.commit= federated_commit;
+ federated_hton.rollback= federated_rollback;
+ federated_hton.create= federated_create_handler;
+ federated_hton.panic= federated_db_end;
+ federated_hton.flags= HTON_ALTER_NOT_SUPPORTED;
+
if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST))
goto error;
if (!hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
@@ -796,6 +767,7 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
{
ulong *lengths;
Field **field;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
DBUG_ENTER("ha_federated::convert_row_to_internal_format");
lengths= mysql_fetch_lengths(stored_result);
@@ -814,12 +786,15 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
(*field)->set_null();
else
{
- (*field)->set_notnull();
- (*field)->store(*row, *lengths, &my_charset_bin);
+ if (bitmap_is_set(table->read_set, (*field)->field_index))
+ {
+ (*field)->set_notnull();
+ (*field)->store(*row, *lengths, &my_charset_bin);
+ }
}
(*field)->move_field_offset(-old_ptr);
}
-
+ dbug_tmp_restore_column_map(table->write_set, old_map);
DBUG_RETURN(0);
}
@@ -1138,22 +1113,25 @@ bool ha_federated::create_where_from_key(String *to,
KEY *key_info,
const key_range *start_key,
const key_range *end_key,
- bool records_in_range)
+ bool records_in_range,
+ bool eq_range)
{
- bool both_not_null=
+ bool both_not_null=
(start_key != NULL && end_key != NULL) ? TRUE : FALSE;
const byte *ptr;
uint remainder, length;
char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE];
String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info);
const key_range *ranges[2]= { start_key, end_key };
+ my_bitmap_map *old_map;
DBUG_ENTER("ha_federated::create_where_from_key");
tmp.length(0);
if (start_key == NULL && end_key == NULL)
DBUG_RETURN(1);
- for (int i= 0; i <= 1; i++)
+ old_map= dbug_tmp_use_all_columns(table, table->write_set);
+ for (uint i= 0; i <= 1; i++)
{
bool needs_quotes;
KEY_PART_INFO *key_part;
@@ -1187,16 +1165,16 @@ bool ha_federated::create_where_from_key(String *to,
{
if (emit_key_part_name(&tmp, key_part) ||
tmp.append(FEDERATED_ISNULL))
- DBUG_RETURN(1);
+ goto err;
continue;
}
}
if (tmp.append(FEDERATED_OPENPAREN))
- DBUG_RETURN(1);
+ goto err;
- switch(ranges[i]->flag) {
- case(HA_READ_KEY_EXACT):
+ switch (ranges[i]->flag) {
+ case HA_READ_KEY_EXACT:
DBUG_PRINT("info", ("federated HA_READ_KEY_EXACT %d", i));
if (store_length >= length ||
!needs_quotes ||
@@ -1204,22 +1182,22 @@ bool ha_federated::create_where_from_key(String *to,
field->result_type() != STRING_RESULT)
{
if (emit_key_part_name(&tmp, key_part))
- DBUG_RETURN(1);
+ goto err;
if (records_in_range)
{
if (tmp.append(FEDERATED_GE))
- DBUG_RETURN(1);
+ goto err;
}
else
{
if (tmp.append(FEDERATED_EQ))
- DBUG_RETURN(1);
+ goto err;
}
if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
part_length))
- DBUG_RETURN(1);
+ goto err;
}
else
{
@@ -1228,43 +1206,49 @@ bool ha_federated::create_where_from_key(String *to,
tmp.append(FEDERATED_LIKE) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 1, ptr,
part_length))
- DBUG_RETURN(1);
+ goto err;
}
break;
- case(HA_READ_AFTER_KEY):
+ case HA_READ_AFTER_KEY:
+ if (eq_range)
+ {
+ if (tmp.append("1=1")) // Dummy
+ goto err;
+ break;
+ }
DBUG_PRINT("info", ("federated HA_READ_AFTER_KEY %d", i));
if (store_length >= length) /* end key */
{
if (emit_key_part_name(&tmp, key_part))
- DBUG_RETURN(1);
+ goto err;
if (i > 0) /* end key */
{
if (tmp.append(FEDERATED_LE))
- DBUG_RETURN(1);
+ goto err;
}
else /* start key */
{
if (tmp.append(FEDERATED_GT))
- DBUG_RETURN(1);
+ goto err;
}
if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
part_length))
{
- DBUG_RETURN(1);
+ goto err;
}
break;
}
- case(HA_READ_KEY_OR_NEXT):
+ case HA_READ_KEY_OR_NEXT:
DBUG_PRINT("info", ("federated HA_READ_KEY_OR_NEXT %d", i));
if (emit_key_part_name(&tmp, key_part) ||
tmp.append(FEDERATED_GE) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
part_length))
- DBUG_RETURN(1);
+ goto err;
break;
- case(HA_READ_BEFORE_KEY):
+ case HA_READ_BEFORE_KEY:
DBUG_PRINT("info", ("federated HA_READ_BEFORE_KEY %d", i));
if (store_length >= length)
{
@@ -1272,23 +1256,23 @@ bool ha_federated::create_where_from_key(String *to,
tmp.append(FEDERATED_LT) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
part_length))
- DBUG_RETURN(1);
+ goto err;
break;
}
- case(HA_READ_KEY_OR_PREV):
+ case HA_READ_KEY_OR_PREV:
DBUG_PRINT("info", ("federated HA_READ_KEY_OR_PREV %d", i));
if (emit_key_part_name(&tmp, key_part) ||
tmp.append(FEDERATED_LE) ||
emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
part_length))
- DBUG_RETURN(1);
+ goto err;
break;
default:
DBUG_PRINT("info",("cannot handle flag %d", ranges[i]->flag));
- DBUG_RETURN(1);
+ goto err;
}
if (tmp.append(FEDERATED_CLOSEPAREN))
- DBUG_RETURN(1);
+ goto err;
next_loop:
if (store_length >= length)
@@ -1298,13 +1282,15 @@ next_loop:
length-= store_length;
ptr+= store_length;
if (tmp.append(FEDERATED_AND))
- DBUG_RETURN(1);
+ goto err;
DBUG_PRINT("info",
("create_where_from_key WHERE clause: %s",
tmp.c_ptr_quick()));
}
}
+ dbug_tmp_restore_column_map(table->write_set, old_map);
+
if (both_not_null)
if (tmp.append(FEDERATED_CLOSEPAREN))
DBUG_RETURN(1);
@@ -1316,6 +1302,10 @@ next_loop:
DBUG_RETURN(1);
DBUG_RETURN(0);
+
+err:
+ dbug_tmp_restore_column_map(table->write_set, old_map);
+ DBUG_RETURN(1);
}
/*
@@ -1355,7 +1345,7 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.append(FEDERATED_BTICK);
query.append(FEDERATED_COMMA);
}
- query.length(query.length()- (FEDERATED_COMMA_LEN - 1));
+ query.length(query.length()- FEDERATED_COMMA_LEN);
query.append(FEDERATED_FROM);
query.append(FEDERATED_BTICK);
@@ -1606,15 +1596,16 @@ int ha_federated::write_row(byte *buf)
String insert_field_value_string(insert_field_value_buffer,
sizeof(insert_field_value_buffer),
&my_charset_bin);
- values_string.length(0);
- insert_string.length(0);
- insert_field_value_string.length(0);
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
DBUG_ENTER("ha_federated::write_row");
DBUG_PRINT("info",
("table charset name %s csname %s",
table->s->table_charset->name,
table->s->table_charset->csname));
+ values_string.length(0);
+ insert_string.length(0);
+ insert_field_value_string.length(0);
statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
@@ -1641,7 +1632,7 @@ int ha_federated::write_row(byte *buf)
for (field= table->field; *field; field++)
{
/* if there is a query id and if it's equal to the current query id */
- if (ha_get_bit_in_write_set((*field)->fieldnr))
+ if (bitmap_is_set(table->write_set, (*field)->field_index))
{
/*
There are some fields. This will be used later to determine
@@ -1666,22 +1657,17 @@ int ha_federated::write_row(byte *buf)
/* append commas between both fields and fieldnames */
/*
- unfortunately, we can't use the logic
- if *(fields + 1) to make the following
- appends conditional because we may not append
- if the next field doesn't match the condition:
- (((*field)->query_id && (*field)->query_id == current_query_id)
+ unfortunately, we can't use the logic if *(fields + 1) to
+ make the following appends conditional as we don't know if the
+ next field is in the write set
*/
insert_string.append(FEDERATED_COMMA);
values_string.append(FEDERATED_COMMA);
}
}
+ dbug_tmp_restore_column_map(table->read_set, old_map);
/*
- remove trailing comma
- */
- insert_string.length(insert_string.length() - strlen(FEDERATED_COMMA));
- /*
if there were no fields, we don't want to add a closing paren
AND, we don't want to chop off the last char '('
insert will be "INSERT INTO t1 VALUES ();"
@@ -1689,9 +1675,13 @@ int ha_federated::write_row(byte *buf)
if (has_fields)
{
/* chops off leading commas */
- values_string.length(values_string.length() - strlen(FEDERATED_COMMA));
+ insert_string.length(insert_string.length() - FEDERATED_COMMA_LEN);
+ values_string.length(values_string.length() - FEDERATED_COMMA_LEN);
insert_string.append(FEDERATED_CLOSEPAREN);
}
+ else
+ insert_string.length(insert_string.length() - FEDERATED_CLOSEPAREN_LEN);
+
/* we always want to append this, even if there aren't any fields */
values_string.append(FEDERATED_CLOSEPAREN);
@@ -1705,8 +1695,8 @@ int ha_federated::write_row(byte *buf)
DBUG_RETURN(stash_remote_error());
}
/*
- If the table we've just written a record to contains an auto_increment field,
- then store the last_insert_id() value from the foreign server
+ If the table we've just written a record to contains an auto_increment
+ field, then store the last_insert_id() value from the foreign server
*/
if (table->next_number_field)
update_auto_increment();
@@ -1728,7 +1718,7 @@ void ha_federated::update_auto_increment(void)
DBUG_ENTER("ha_federated::update_auto_increment");
thd->insert_id(mysql->last_used_con->insert_id);
- DBUG_PRINT("info",("last_insert_id %d", auto_increment_value));
+ DBUG_PRINT("info",("last_insert_id %d", stats.auto_increment_value));
DBUG_VOID_RETURN;
}
@@ -1816,7 +1806,7 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
this? Because we only are updating one record, and LIMIT enforces
this.
*/
- bool has_a_primary_key= (table->s->primary_key == 0 ? TRUE : FALSE);
+ bool has_a_primary_key= test(table->s->primary_key != MAX_KEY);
/*
buffers for following strings
*/
@@ -1868,48 +1858,52 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
for (Field **field= table->field; *field; field++)
{
- where_string.append((*field)->field_name);
- update_string.append((*field)->field_name);
- update_string.append(FEDERATED_EQ);
-
- if ((*field)->is_null())
- new_field_value.append(FEDERATED_NULL);
- else
- {
- /* otherwise = */
- (*field)->val_str(&new_field_value);
- (*field)->quote_data(&new_field_value);
-
- if (!field_in_record_is_null(table, *field, (char*) old_data))
- where_string.append(FEDERATED_EQ);
- }
-
- if (field_in_record_is_null(table, *field, (char*) old_data))
- where_string.append(FEDERATED_ISNULL);
- else
+ if (bitmap_is_set(table->write_set, (*field)->field_index))
{
- (*field)->val_str(&old_field_value,
- (char*) (old_data + (*field)->offset()));
- (*field)->quote_data(&old_field_value);
- where_string.append(old_field_value);
+ if ((*field)->is_null())
+ new_field_value.append(FEDERATED_NULL);
+ else
+ {
+ my_bitmap_map *old_map= tmp_use_all_columns(table, table->read_set);
+ /* otherwise = */
+ (*field)->val_str(&new_field_value);
+ (*field)->quote_data(&new_field_value);
+ tmp_restore_column_map(table->read_set, old_map);
+ }
+ update_string.append((*field)->field_name);
+ update_string.append(FEDERATED_EQ);
+ update_string.append(new_field_value);
+ update_string.append(FEDERATED_COMMA);
+ new_field_value.length(0);
}
- update_string.append(new_field_value);
- new_field_value.length(0);
-
- /*
- Only append conjunctions if we have another field in which
- to iterate
- */
- if (*(field + 1))
+ if (bitmap_is_set(table->read_set, (*field)->field_index))
{
- update_string.append(FEDERATED_COMMA);
+ where_string.append((*field)->field_name);
+ if (field_in_record_is_null(table, *field, (char*) old_data))
+ where_string.append(FEDERATED_ISNULL);
+ else
+ {
+ where_string.append(FEDERATED_EQ);
+ (*field)->val_str(&old_field_value,
+ (char*) (old_data + (*field)->offset()));
+ (*field)->quote_data(&old_field_value);
+ where_string.append(old_field_value);
+ old_field_value.length(0);
+ }
where_string.append(FEDERATED_AND);
}
- old_field_value.length(0);
}
- update_string.append(FEDERATED_WHERE);
- update_string.append(where_string);
+
+ /* Remove last ', '. This works as there must be at least on updated field */
+ update_string.length(update_string.length() - FEDERATED_COMMA_LEN);
+ if (where_string.length())
+ {
+ where_string.length(where_string.length() - FEDERATED_AND_LEN);
+ update_string.append(FEDERATED_WHERE);
+ update_string.append(where_string);
+ }
+
/*
If this table has not a primary key, then we could possibly
update multiple rows. We want to make sure to only update one!
@@ -1943,9 +1937,9 @@ int ha_federated::delete_row(const byte *buf)
{
char delete_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char data_buffer[FEDERATED_QUERY_BUFFER_SIZE];
-
String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin);
String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin);
+ uint found= 0;
DBUG_ENTER("ha_federated::delete_row");
delete_string.length(0);
@@ -1959,25 +1953,31 @@ int ha_federated::delete_row(const byte *buf)
for (Field **field= table->field; *field; field++)
{
Field *cur_field= *field;
- data_string.length(0);
- delete_string.append(cur_field->field_name);
-
- if (cur_field->is_null())
- {
- delete_string.append(FEDERATED_IS);
- data_string.append(FEDERATED_NULL);
- }
- else
+ found++;
+ if (bitmap_is_set(table->read_set, cur_field->field_index))
{
- delete_string.append(FEDERATED_EQ);
- cur_field->val_str(&data_string);
- cur_field->quote_data(&data_string);
+ data_string.length(0);
+ delete_string.append(cur_field->field_name);
+ if (cur_field->is_null())
+ {
+ delete_string.append(FEDERATED_IS);
+ delete_string.append(FEDERATED_NULL);
+ }
+ else
+ {
+ delete_string.append(FEDERATED_EQ);
+ cur_field->val_str(&data_string);
+ cur_field->quote_data(&data_string);
+ delete_string.append(data_string);
+ }
+ delete_string.append(FEDERATED_AND);
}
-
- delete_string.append(data_string);
- delete_string.append(FEDERATED_AND);
}
- delete_string.length(delete_string.length()-5); // Remove trailing AND
+
+ // Remove trailing AND
+ delete_string.length(delete_string.length() - FEDERATED_AND_LEN);
+ if (!found)
+ delete_string.length(delete_string.length() - FEDERATED_WHERE_LEN);
delete_string.append(FEDERATED_LIMIT1);
DBUG_PRINT("info",
@@ -1986,10 +1986,10 @@ int ha_federated::delete_row(const byte *buf)
{
DBUG_RETURN(stash_remote_error());
}
- deleted+= mysql->affected_rows;
+ stats.deleted+= mysql->affected_rows;
DBUG_PRINT("info",
("rows deleted %d rows deleted for all time %d",
- int(mysql->affected_rows), deleted));
+ int(mysql->affected_rows), stats.deleted));
DBUG_RETURN(0);
}
@@ -2050,7 +2050,7 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
create_where_from_key(&index_string,
&table->key_info[index],
&range,
- NULL, 0);
+ NULL, 0, 0);
sql_query.append(index_string);
DBUG_PRINT("info",
@@ -2112,15 +2112,10 @@ int ha_federated::index_init(uint keynr, bool sorted)
DBUG_RETURN(0);
}
-/*
- int read_range_first(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted);
-*/
int ha_federated::read_range_first(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted)
+ const key_range *end_key,
+ bool eq_range, bool sorted)
{
char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
int retval;
@@ -2136,7 +2131,7 @@ int ha_federated::read_range_first(const key_range *start_key,
sql_query.append(share->select_query);
create_where_from_key(&sql_query,
&table->key_info[active_index],
- start_key, end_key, 0);
+ start_key, end_key, 0, eq_range);
if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
{
@@ -2481,18 +2476,20 @@ void ha_federated::info(uint flag)
delete_length = ?
*/
if (row[4] != NULL)
- records= (ha_rows) my_strtoll10(row[4], (char**) 0, &error);
+ stats.records= (ha_rows) my_strtoll10(row[4], (char**) 0,
+ &error);
if (row[5] != NULL)
- mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0, &error);
+ stats.mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0,
+ &error);
if (row[12] != NULL)
- update_time= (ha_rows) my_strtoll10(row[12], (char**) 0, &error);
+ stats.update_time= (ha_rows) my_strtoll10(row[12], (char**) 0,
+ &error);
if (row[13] != NULL)
- check_time= (ha_rows) my_strtoll10(row[13], (char**) 0, &error);
+ stats.check_time= (ha_rows) my_strtoll10(row[13], (char**) 0,
+ &error);
}
if (flag & HA_STATUS_CONST)
- {
- block_size= 4096;
- }
+ stats.block_size= 4096;
}
if (result)
@@ -2543,8 +2540,8 @@ int ha_federated::delete_all_rows()
{
DBUG_RETURN(stash_remote_error());
}
- deleted+= records;
- records= 0;
+ stats.deleted+= stats.records;
+ stats.records= 0;
DBUG_RETURN(0);
}
@@ -2797,7 +2794,7 @@ int ha_federated::connection_autocommit(bool state)
DBUG_ENTER("ha_federated::connection_autocommit");
text= (state == true) ? "SET AUTOCOMMIT=1" : "SET AUTOCOMMIT=0";
DBUG_RETURN(execute_simple_query(text, 16));
-}
+}
int ha_federated::execute_simple_query(const char *query, int len)
@@ -2811,17 +2808,20 @@ int ha_federated::execute_simple_query(const char *query, int len)
DBUG_RETURN(0);
}
+struct st_mysql_storage_engine federated_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &federated_hton };
mysql_declare_plugin(federated)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &federated_hton,
- federated_hton_name,
+ &federated_storage_engine,
+ "FEDERATED",
"Patrick Galbraith and Brian Aker, MySQL AB",
- federated_hton_comment,
- NULL, /* Plugin Init */
+ "Federated MySQL storage engine",
+ federated_db_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
+ 0
}
mysql_declare_plugin_end;
diff --git a/sql/ha_federated.h b/sql/ha_federated.h
index 458ef42ebda..4a4561ba274 100644
--- a/sql/ha_federated.h
+++ b/sql/ha_federated.h
@@ -39,83 +39,83 @@
#define FEDERATED_RECORDS_IN_RANGE 2
#define FEDERATED_INFO " SHOW TABLE STATUS LIKE "
-#define FEDERATED_INFO_LEN sizeof(FEDERATED_INFO)
+#define FEDERATED_INFO_LEN (sizeof(FEDERATED_INFO) -1)
#define FEDERATED_SELECT "SELECT "
-#define FEDERATED_SELECT_LEN sizeof(FEDERATED_SELECT)
+#define FEDERATED_SELECT_LEN (sizeof(FEDERATED_SELECT) -1)
#define FEDERATED_WHERE " WHERE "
-#define FEDERATED_WHERE_LEN sizeof(FEDERATED_WHERE)
+#define FEDERATED_WHERE_LEN (sizeof(FEDERATED_WHERE) -1)
#define FEDERATED_FROM " FROM "
-#define FEDERATED_FROM_LEN sizeof(FEDERATED_FROM)
+#define FEDERATED_FROM_LEN (sizeof(FEDERATED_FROM) -1)
#define FEDERATED_PERCENT "%"
-#define FEDERATED_PERCENT_LEN sizeof(FEDERATED_PERCENT)
+#define FEDERATED_PERCENT_LEN (sizeof(FEDERATED_PERCENT) -1)
#define FEDERATED_IS " IS "
-#define FEDERATED_IS_LEN sizeof(FEDERATED_IS)
+#define FEDERATED_IS_LEN (sizeof(FEDERATED_IS) -1)
#define FEDERATED_NULL " NULL "
-#define FEDERATED_NULL_LEN sizeof(FEDERATED_NULL)
+#define FEDERATED_NULL_LEN (sizeof(FEDERATED_NULL) -1)
#define FEDERATED_ISNULL " IS NULL "
-#define FEDERATED_ISNULL_LEN sizeof(FEDERATED_ISNULL)
+#define FEDERATED_ISNULL_LEN (sizeof(FEDERATED_ISNULL) -1)
#define FEDERATED_LIKE " LIKE "
-#define FEDERATED_LIKE_LEN sizeof(FEDERATED_LIKE)
+#define FEDERATED_LIKE_LEN (sizeof(FEDERATED_LIKE) -1)
#define FEDERATED_TRUNCATE "TRUNCATE "
-#define FEDERATED_TRUNCATE_LEN sizeof(FEDERATED_TRUNCATE)
+#define FEDERATED_TRUNCATE_LEN (sizeof(FEDERATED_TRUNCATE) -1)
#define FEDERATED_DELETE "DELETE "
-#define FEDERATED_DELETE_LEN sizeof(FEDERATED_DELETE)
+#define FEDERATED_DELETE_LEN (sizeof(FEDERATED_DELETE) -1)
#define FEDERATED_INSERT "INSERT INTO "
-#define FEDERATED_INSERT_LEN sizeof(FEDERATED_INSERT)
+#define FEDERATED_INSERT_LEN (sizeof(FEDERATED_INSERT) -1)
#define FEDERATED_OPTIMIZE "OPTIMIZE TABLE "
-#define FEDERATED_OPTIMIZE_LEN sizeof(FEDERATED_OPTIMIZE)
+#define FEDERATED_OPTIMIZE_LEN (sizeof(FEDERATED_OPTIMIZE) -1)
#define FEDERATED_REPAIR "REPAIR TABLE "
-#define FEDERATED_REPAIR_LEN sizeof(FEDERATED_REPAIR)
+#define FEDERATED_REPAIR_LEN (sizeof(FEDERATED_REPAIR) -1)
#define FEDERATED_QUICK " QUICK"
-#define FEDERATED_QUICK_LEN sizeof(FEDERATED_QUICK)
+#define FEDERATED_QUICK_LEN (sizeof(FEDERATED_QUICK) -1)
#define FEDERATED_EXTENDED " EXTENDED"
-#define FEDERATED_EXTENDED_LEN sizeof(FEDERATED_EXTENDED)
+#define FEDERATED_EXTENDED_LEN (sizeof(FEDERATED_EXTENDED) -1)
#define FEDERATED_USE_FRM " USE_FRM"
-#define FEDERATED_USE_FRM_LEN sizeof(FEDERATED_USE_FRM)
+#define FEDERATED_USE_FRM_LEN (sizeof(FEDERATED_USE_FRM) -1)
#define FEDERATED_LIMIT1 " LIMIT 1"
-#define FEDERATED_LIMIT1_LEN sizeof(FEDERATED_LIMIT1)
+#define FEDERATED_LIMIT1_LEN (sizeof(FEDERATED_LIMIT1) -1)
#define FEDERATED_VALUES "VALUES "
-#define FEDERATED_VALUES_LEN sizeof(FEDERATED_VALUES)
+#define FEDERATED_VALUES_LEN (sizeof(FEDERATED_VALUES) -1)
#define FEDERATED_UPDATE "UPDATE "
-#define FEDERATED_UPDATE_LEN sizeof(FEDERATED_UPDATE)
-#define FEDERATED_SET "SET "
-#define FEDERATED_SET_LEN sizeof(FEDERATED_SET)
+#define FEDERATED_UPDATE_LEN (sizeof(FEDERATED_UPDATE) -1)
+#define FEDERATED_SET " SET "
+#define FEDERATED_SET_LEN (sizeof(FEDERATED_SET) -1)
#define FEDERATED_AND " AND "
-#define FEDERATED_AND_LEN sizeof(FEDERATED_AND)
+#define FEDERATED_AND_LEN (sizeof(FEDERATED_AND) -1)
#define FEDERATED_CONJUNCTION ") AND ("
-#define FEDERATED_CONJUNCTION_LEN sizeof(FEDERATED_CONJUNCTION)
+#define FEDERATED_CONJUNCTION_LEN (sizeof(FEDERATED_CONJUNCTION) -1)
#define FEDERATED_OR " OR "
-#define FEDERATED_OR_LEN sizeof(FEDERATED_OR)
+#define FEDERATED_OR_LEN (sizeof(FEDERATED_OR) -1)
#define FEDERATED_NOT " NOT "
-#define FEDERATED_NOT_LEN sizeof(FEDERATED_NOT)
+#define FEDERATED_NOT_LEN (sizeof(FEDERATED_NOT) -1)
#define FEDERATED_STAR "* "
-#define FEDERATED_STAR_LEN sizeof(FEDERATED_STAR)
+#define FEDERATED_STAR_LEN (sizeof(FEDERATED_STAR) -1)
#define FEDERATED_SPACE " "
-#define FEDERATED_SPACE_LEN sizeof(FEDERATED_SPACE)
+#define FEDERATED_SPACE_LEN (sizeof(FEDERATED_SPACE) -1)
#define FEDERATED_SQUOTE "'"
-#define FEDERATED_SQUOTE_LEN sizeof(FEDERATED_SQUOTE)
+#define FEDERATED_SQUOTE_LEN (sizeof(FEDERATED_SQUOTE) -1)
#define FEDERATED_COMMA ", "
-#define FEDERATED_COMMA_LEN sizeof(FEDERATED_COMMA)
+#define FEDERATED_COMMA_LEN (sizeof(FEDERATED_COMMA) -1)
#define FEDERATED_BTICK "`"
-#define FEDERATED_BTICK_LEN sizeof(FEDERATED_BTICK)
+#define FEDERATED_BTICK_LEN (sizeof(FEDERATED_BTICK) -1)
#define FEDERATED_OPENPAREN " ("
-#define FEDERATED_OPENPAREN_LEN sizeof(FEDERATED_OPENPAREN)
+#define FEDERATED_OPENPAREN_LEN (sizeof(FEDERATED_OPENPAREN) -1)
#define FEDERATED_CLOSEPAREN ") "
-#define FEDERATED_CLOSEPAREN_LEN sizeof(FEDERATED_CLOSEPAREN)
+#define FEDERATED_CLOSEPAREN_LEN (sizeof(FEDERATED_CLOSEPAREN) -1)
#define FEDERATED_NE " != "
-#define FEDERATED_NE_LEN sizeof(FEDERATED_NE)
+#define FEDERATED_NE_LEN (sizeof(FEDERATED_NE) -1)
#define FEDERATED_GT " > "
-#define FEDERATED_GT_LEN sizeof(FEDERATED_GT)
+#define FEDERATED_GT_LEN (sizeof(FEDERATED_GT) -1)
#define FEDERATED_LT " < "
-#define FEDERATED_LT_LEN sizeof(FEDERATED_LT)
+#define FEDERATED_LT_LEN (sizeof(FEDERATED_LT) -1)
#define FEDERATED_LE " <= "
-#define FEDERATED_LE_LEN sizeof(FEDERATED_LE)
+#define FEDERATED_LE_LEN (sizeof(FEDERATED_LE) -1)
#define FEDERATED_GE " >= "
-#define FEDERATED_GE_LEN sizeof(FEDERATED_GE)
+#define FEDERATED_GE_LEN (sizeof(FEDERATED_GE) -1)
#define FEDERATED_EQ " = "
-#define FEDERATED_EQ_LEN sizeof(FEDERATED_EQ)
+#define FEDERATED_EQ_LEN (sizeof(FEDERATED_EQ) -1)
#define FEDERATED_FALSE " 1=0"
-#define FEDERATED_FALSE_LEN sizeof(FEDERATED_FALSE)
+#define FEDERATED_FALSE_LEN (sizeof(FEDERATED_FALSE) -1)
/*
FEDERATED_SHARE is a structure that will be shared amoung all open handlers
@@ -168,7 +168,7 @@ private:
bool create_where_from_key(String *to, KEY *key_info,
const key_range *start_key,
const key_range *end_key,
- bool records_in_range);
+ bool records_in_range, bool eq_range);
int stash_remote_error();
public:
@@ -192,12 +192,12 @@ public:
implements. The current table flags are documented in
handler.h
*/
- ulong table_flags() const
+ ulonglong table_flags() const
{
/* fix server to be able to get remote server table flags */
- return (HA_NOT_EXACT_COUNT |
- HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | HA_REC_NOT_IN_SEQ |
- HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS| HA_NO_PREFIX_CHAR_KEYS);
+ return (HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | HA_REC_NOT_IN_SEQ |
+ HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS| HA_NO_PREFIX_CHAR_KEYS |
+ HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | HA_PARTIAL_COLUMN_READ);
}
/*
This is a bitmap of flags that says how the storage engine
@@ -231,8 +231,8 @@ public:
*/
double scan_time()
{
- DBUG_PRINT("info", ("records %lu", (ulong) records));
- return (double)(records*1000);
+ DBUG_PRINT("info", ("records %lu", (ulong) stats.records));
+ return (double)(stats.records*1000);
}
/*
The next method will never be called if you do not implement indexes.
@@ -302,11 +302,10 @@ public:
int external_lock(THD *thd, int lock_type);
int connection_commit();
int connection_rollback();
- bool has_transactions() { return 1; }
int connection_autocommit(bool state);
int execute_simple_query(const char *query, int len);
};
-bool federated_db_init(void);
+int federated_db_init(void);
int federated_db_end(ha_panic_function type);
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 1a7efb42748..3a2027afaba 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -24,53 +24,23 @@
#include "ha_heap.h"
-static handler *heap_create_handler(TABLE_SHARE *table);
-
-static const char heap_hton_name[]= "MEMORY";
-static const char heap_hton_comment[]=
- "Hash based, stored in memory, useful for temporary tables";
-
-handlerton heap_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- heap_hton_name,
- SHOW_OPTION_YES,
- heap_hton_comment,
- DB_TYPE_HEAP,
- NULL,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- heap_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- heap_panic, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill Files Table */
- HTON_CAN_RECREATE,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
+static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
+
+handlerton heap_hton;
+
+int heap_init()
+{
+ heap_hton.state= SHOW_OPTION_YES;
+ heap_hton.db_type= DB_TYPE_HEAP;
+ heap_hton.create= heap_create_handler;
+ heap_hton.panic= heap_panic;
+ heap_hton.flags= HTON_CAN_RECREATE;
+ return 0;
+}
-static handler *heap_create_handler(TABLE_SHARE *table)
+static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_heap(table);
+ return new (mem_root) ha_heap(table);
}
@@ -361,16 +331,16 @@ void ha_heap::info(uint flag)
HEAPINFO info;
(void) heap_info(file,&info,flag);
- records = info.records;
- deleted = info.deleted;
- errkey = info.errkey;
- mean_rec_length=info.reclength;
- data_file_length=info.data_length;
- index_file_length=info.index_length;
- max_data_file_length= info.max_records* info.reclength;
- delete_length= info.deleted * info.reclength;
+ errkey= info.errkey;
+ stats.records = info.records;
+ stats.deleted = info.deleted;
+ stats.mean_rec_length=info.reclength;
+ stats.data_file_length=info.data_length;
+ stats.index_file_length=info.index_length;
+ stats.max_data_file_length= info.max_records* info.reclength;
+ stats.delete_length= info.deleted * info.reclength;
if (flag & HA_STATUS_AUTO)
- auto_increment_value= info.auto_increment;
+ stats.auto_increment_value= info.auto_increment;
/*
If info() is called for the first time after open(), we will still
have to update the key statistics. Hoping that a table lock is now
@@ -380,11 +350,19 @@ void ha_heap::info(uint flag)
update_key_stats();
}
+
int ha_heap::extra(enum ha_extra_function operation)
{
return heap_extra(file,operation);
}
+
+int ha_heap::reset()
+{
+ return heap_reset(file);
+}
+
+
int ha_heap::delete_all_rows()
{
heap_clear(file);
@@ -561,8 +539,8 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
max_key->flag != HA_READ_AFTER_KEY)
return HA_POS_ERROR; // Can only use exact keys
- if (records <= 1)
- return records;
+ if (stats.records <= 1)
+ return stats.records;
/* Assert that info() did run. We need current statistics here. */
DBUG_ASSERT(key_stat_version == file->s->key_stat_version);
@@ -690,13 +668,18 @@ void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
{
table->file->info(HA_STATUS_AUTO);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
- create_info->auto_increment_value= auto_increment_value;
+ create_info->auto_increment_value= stats.auto_increment_value;
}
-ulonglong ha_heap::get_auto_increment()
+void ha_heap::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
ha_heap::info(HA_STATUS_AUTO);
- return auto_increment_value;
+ *first_value= stats.auto_increment_value;
+ /* such table has only table-level locking so reserves up to +inf */
+ *nb_reserved_values= ULONGLONG_MAX;
}
@@ -711,14 +694,17 @@ bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
+struct st_mysql_storage_engine heap_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &heap_hton};
+
mysql_declare_plugin(heap)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &heap_hton,
- heap_hton_name,
+ &heap_storage_engine,
+ "MEMORY",
"MySQL AB",
- heap_hton_comment,
- NULL,
+ "Hash based, stored in memory, useful for temporary tables",
+ heap_init,
NULL,
0x0100, /* 1.0 */
0
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 9b9b7f90d90..00e59856f26 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -46,11 +46,11 @@ public:
/* Rows also use a fixed-size format */
enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
const char **bas_ext() const;
- ulong table_flags() const
+ ulonglong table_flags() const
{
return (HA_FAST_KEY_READ | HA_NO_BLOBS | HA_NULL_IN_KEY |
- HA_REC_NOT_IN_SEQ | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED);
+ HA_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED | HA_NO_TRANSACTIONS |
+ HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
}
ulong index_flags(uint inx, uint part, bool all_parts) const
{
@@ -61,7 +61,8 @@ public:
const key_map *keys_to_use_for_scanning() { return &btree_keys; }
uint max_supported_keys() const { return MAX_KEY; }
uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
- double scan_time() { return (double) (records+deleted) / 20.0+10; }
+ double scan_time()
+ { return (double) (stats.records+stats.deleted) / 20.0+10; }
double read_time(uint index, uint ranges, ha_rows rows)
{ return (double) rows / 20.0+1; }
@@ -71,7 +72,10 @@ public:
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
- ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
@@ -87,6 +91,7 @@ public:
void position(const byte *record);
void info(uint);
int extra(enum ha_extra_function operation);
+ int reset();
int external_lock(THD *thd, int lock_type);
int delete_all_rows(void);
int disable_indexes(uint mode);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 0b2f561e8c9..742f9ce7631 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -43,6 +43,7 @@ have disables the InnoDB inlining in this file. */
#define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
#ifdef WITH_INNOBASE_STORAGE_ENGINE
+
#include "ha_innodb.h"
pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */
@@ -203,54 +204,15 @@ static int innobase_rollback(THD* thd, bool all);
static int innobase_rollback_to_savepoint(THD* thd, void *savepoint);
static int innobase_savepoint(THD* thd, void *savepoint);
static int innobase_release_savepoint(THD* thd, void *savepoint);
-static handler *innobase_create_handler(TABLE_SHARE *table);
+static handler *innobase_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
static const char innobase_hton_name[]= "InnoDB";
-static const char innobase_hton_comment[]=
- "Supports transactions, row-level locking, and foreign keys";
-
-handlerton innobase_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- innobase_hton_name,
- SHOW_OPTION_YES,
- innobase_hton_comment,
- DB_TYPE_INNODB,
- innobase_init,
- 0, /* slot */
- sizeof(trx_named_savept_t), /* savepoint size. TODO: use it */
- innobase_close_connection,
- innobase_savepoint,
- innobase_rollback_to_savepoint,
- innobase_release_savepoint,
- innobase_commit, /* commit */
- innobase_rollback, /* rollback */
- innobase_xa_prepare, /* prepare */
- innobase_xa_recover, /* recover */
- innobase_commit_by_xid, /* commit_by_xid */
- innobase_rollback_by_xid, /* rollback_by_xid */
- innobase_create_cursor_view,
- innobase_set_cursor_view,
- innobase_close_cursor_view,
- innobase_create_handler, /* Create a new handler */
- innobase_drop_database, /* Drop a database */
- innobase_end, /* Panic call */
- innobase_start_trx_and_assign_read_view, /* Start Consistent Snapshot */
- innobase_flush_logs, /* Flush logs */
- innobase_show_status, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* alter_tablespace */
- NULL, /* Fill FILES table */
- HTON_NO_FLAGS,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- innobase_release_temporary_latches
-};
+handlerton innobase_hton;
-
-static handler *innobase_create_handler(TABLE_SHARE *table)
+static handler *innobase_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_innobase(table);
+ return new (mem_root) ha_innobase(table);
}
@@ -843,10 +805,9 @@ ha_innobase::ha_innobase(TABLE_SHARE *table_arg)
HA_NULL_IN_KEY |
HA_CAN_INDEX_BLOBS |
HA_CAN_SQL_HANDLER |
- HA_NOT_EXACT_COUNT |
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS |
+ HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
HA_PRIMARY_KEY_IN_READ_INDEX |
- HA_CAN_GEOMETRY |
+ HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
HA_TABLE_SCAN_ON_INDEX),
start_of_scan(0),
num_write_row(0)
@@ -1230,10 +1191,9 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/*************************************************************************
Opens an InnoDB database. */
-bool
+int
innobase_init(void)
/*===============*/
- /* out: &innobase_hton, or NULL on error */
{
static char current_dir[3]; /* Set if using current lib */
int err;
@@ -1242,8 +1202,33 @@ innobase_init(void)
DBUG_ENTER("innobase_init");
+ innobase_hton.state=have_innodb;
+ innobase_hton.db_type= DB_TYPE_INNODB;
+ innobase_hton.savepoint_offset=sizeof(trx_named_savept_t);
+ innobase_hton.close_connection=innobase_close_connection;
+ innobase_hton.savepoint_set=innobase_savepoint;
+ innobase_hton.savepoint_rollback=innobase_rollback_to_savepoint;
+ innobase_hton.savepoint_release=innobase_release_savepoint;
+ innobase_hton.commit=innobase_commit;
+ innobase_hton.rollback=innobase_rollback;
+ innobase_hton.prepare=innobase_xa_prepare;
+ innobase_hton.recover=innobase_xa_recover;
+ innobase_hton.commit_by_xid=innobase_commit_by_xid;
+ innobase_hton.rollback_by_xid=innobase_rollback_by_xid;
+ innobase_hton.create_cursor_read_view=innobase_create_cursor_view;
+ innobase_hton.set_cursor_read_view=innobase_set_cursor_view;
+ innobase_hton.close_cursor_read_view=innobase_close_cursor_view;
+ innobase_hton.create=innobase_create_handler;
+ innobase_hton.drop_database=innobase_drop_database;
+ innobase_hton.panic=innobase_end;
+ innobase_hton.start_consistent_snapshot=innobase_start_trx_and_assign_read_view;
+ innobase_hton.flush_logs=innobase_flush_logs;
+ innobase_hton.show_status=innobase_show_status;
+ innobase_hton.flags=HTON_NO_FLAGS;
+ innobase_hton.release_temporary_latches=innobase_release_temporary_latches;
+
if (have_innodb != SHOW_OPTION_YES)
- goto error;
+ DBUG_RETURN(0); // nothing else to do
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -2322,7 +2307,7 @@ ha_innobase::open(
}
}
- block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
+ stats.block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
in query optimization */
/* Init table lock structure */
@@ -2917,16 +2902,15 @@ ha_innobase::store_key_val_for_row(
/******************************************************************
Builds a 'template' to the prebuilt struct. The template is used in fast
retrieval of just those column values MySQL needs in its processing. */
-static
void
-build_template(
+ha_innobase::build_template(
/*===========*/
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
THD* thd, /* in: current user thread, used
only if templ_type is
ROW_MYSQL_REC_FIELDS */
TABLE* table, /* in: MySQL table */
- ulint templ_type) /* in: ROW_MYSQL_WHOLE_ROW or
+ uint templ_type) /* in: ROW_MYSQL_WHOLE_ROW or
ROW_MYSQL_REC_FIELDS */
{
dict_index_t* index;
@@ -3035,8 +3019,8 @@ build_template(
goto include_field;
}
- if (table->file->ha_get_bit_in_read_set(i+1) ||
- table->file->ha_get_bit_in_write_set(i+1)) {
+ if (bitmap_is_set(table->read_set, i) ||
+ bitmap_is_set(table->write_set, i)) {
/* This field is needed in the query */
goto include_field;
@@ -5420,7 +5404,7 @@ ha_innobase::info(
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
if (os_file_get_status(path,&stat_info)) {
- create_time = stat_info.ctime;
+ stats.create_time = stat_info.ctime;
}
}
@@ -5448,21 +5432,21 @@ ha_innobase::info(
n_rows++;
}
- records = (ha_rows)n_rows;
- deleted = 0;
- data_file_length = ((ulonglong)
+ stats.records = (ha_rows)n_rows;
+ stats.deleted = 0;
+ stats.data_file_length = ((ulonglong)
ib_table->stat_clustered_index_size)
* UNIV_PAGE_SIZE;
- index_file_length = ((ulonglong)
+ stats.index_file_length = ((ulonglong)
ib_table->stat_sum_of_other_index_sizes)
* UNIV_PAGE_SIZE;
- delete_length = 0;
- check_time = 0;
+ stats.delete_length = 0;
+ stats.check_time = 0;
- if (records == 0) {
- mean_rec_length = 0;
+ if (stats.records == 0) {
+ stats.mean_rec_length = 0;
} else {
- mean_rec_length = (ulong) (data_file_length / records);
+ stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
}
}
@@ -5511,9 +5495,9 @@ ha_innobase::info(
if (index->stat_n_diff_key_vals[j + 1] == 0) {
- rec_per_key = records;
+ rec_per_key = stats.records;
} else {
- rec_per_key = (ha_rows)(records /
+ rec_per_key = (ha_rows)(stats.records /
index->stat_n_diff_key_vals[j + 1]);
}
@@ -5568,7 +5552,7 @@ ha_innobase::info(
}
}
- auto_increment_value = auto_inc;
+ stats.auto_increment_value = auto_inc;
}
prebuilt->trx->op_info = (char*)"";
@@ -5963,8 +5947,7 @@ ha_innobase::extra(
/*===============*/
/* out: 0 or error number */
enum ha_extra_function operation)
- /* in: HA_EXTRA_RETRIEVE_ALL_COLS or some
- other flag */
+ /* in: HA_EXTRA_FLUSH or some other flag */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
@@ -5978,13 +5961,6 @@ ha_innobase::extra(
row_mysql_prebuilt_free_blob_heap(prebuilt);
}
break;
- case HA_EXTRA_RESET:
- if (prebuilt->blob_heap) {
- row_mysql_prebuilt_free_blob_heap(prebuilt);
- }
- prebuilt->keep_other_fields_on_keyread = 0;
- prebuilt->read_just_key = 0;
- break;
case HA_EXTRA_RESET_STATE:
prebuilt->keep_other_fields_on_keyread = 0;
prebuilt->read_just_key = 0;
@@ -5992,16 +5968,6 @@ ha_innobase::extra(
case HA_EXTRA_NO_KEYREAD:
prebuilt->read_just_key = 0;
break;
- case HA_EXTRA_RETRIEVE_ALL_COLS:
- prebuilt->hint_need_to_fetch_extra_cols
- = ROW_RETRIEVE_ALL_COLS;
- break;
- case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
- if (prebuilt->hint_need_to_fetch_extra_cols == 0) {
- prebuilt->hint_need_to_fetch_extra_cols
- = ROW_RETRIEVE_PRIMARY_KEY;
- }
- break;
case HA_EXTRA_KEYREAD:
prebuilt->read_just_key = 1;
break;
@@ -6015,6 +5981,18 @@ ha_innobase::extra(
return(0);
}
+int ha_innobase::reset()
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ if (prebuilt->blob_heap) {
+ row_mysql_prebuilt_free_blob_heap(prebuilt);
+ }
+ prebuilt->keep_other_fields_on_keyread = 0;
+ prebuilt->read_just_key = 0;
+ return 0;
+}
+
+
/**********************************************************************
MySQL calls this function at the start of each SQL statement inside LOCK
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
@@ -6473,7 +6451,7 @@ innodb_show_status(
bool result = FALSE;
- if (stat_print(thd, innobase_hton.name, strlen(innobase_hton.name),
+ if (stat_print(thd, innobase_hton_name, strlen(innobase_hton_name),
STRING_WITH_LEN(""), str, flen)) {
result= TRUE;
}
@@ -6500,7 +6478,7 @@ innodb_mutex_show_status(
ulint rw_lock_count_os_wait= 0;
ulint rw_lock_count_os_yield= 0;
ulonglong rw_lock_wait_time= 0;
- uint hton_name_len= strlen(innobase_hton.name), buf1len, buf2len;
+ uint hton_name_len= strlen(innobase_hton_name), buf1len, buf2len;
DBUG_ENTER("innodb_mutex_show_status");
#ifdef MUTEX_PROTECT_TO_BE_ADDED_LATER
@@ -6527,7 +6505,7 @@ innodb_mutex_show_status(
mutex->count_os_yield,
mutex->lspent_time/1000);
- if (stat_print(thd, innobase_hton.name,
+ if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
buf2, buf2len)) {
#ifdef MUTEX_PROTECT_TO_BE_ADDED_LATER
@@ -6557,7 +6535,7 @@ innodb_mutex_show_status(
rw_lock_count_os_wait, rw_lock_count_os_yield,
rw_lock_wait_time/1000);
- if (stat_print(thd, innobase_hton.name, hton_name_len,
+ if (stat_print(thd, innobase_hton_name, hton_name_len,
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
DBUG_RETURN(1);
}
@@ -6963,17 +6941,21 @@ func_exit_early:
return(error);
}
-/***********************************************************************
+/*******************************************************************************
This function initializes the auto-inc counter if it has not been
initialized yet. This function does not change the value of the auto-inc
counter if it already has been initialized. Returns the value of the
-auto-inc counter. */
+auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as
+we have a table-level lock). offset, increment, nb_desired_values are ignored.
+*first_value is set to -1 if error (deadlock or lock wait timeout) */
-ulonglong
-ha_innobase::get_auto_increment()
-/*=============================*/
- /* out: auto-increment column value, -1 if error
- (deadlock or lock wait timeout) */
+void ha_innobase::get_auto_increment(
+/*=================================*/
+ ulonglong offset, /* in */
+ ulonglong increment, /* in */
+ ulonglong nb_desired_values, /* in */
+ ulonglong *first_value, /* out */
+ ulonglong *nb_reserved_values) /* out */
{
longlong nr;
int error;
@@ -6988,10 +6970,13 @@ ha_innobase::get_auto_increment()
ut_print_timestamp(stderr);
sql_print_error("Error %lu in ::get_auto_increment()",
(ulong) error);
- return(~(ulonglong) 0);
+ *first_value= (~(ulonglong) 0);
+ return;
}
- return((ulonglong) nr);
+ *first_value= (ulonglong) nr;
+ /* table-level autoinc lock reserves up to +inf */
+ *nb_reserved_values= ULONGLONG_MAX;
}
/* See comment in handler.h */
@@ -7459,15 +7444,17 @@ bool ha_innobase::check_if_incompatible_data(
return COMPATIBLE_DATA_YES;
}
+struct st_mysql_storage_engine innobase_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &innobase_hton};
mysql_declare_plugin(innobase)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &innobase_hton,
+ &innobase_storage_engine,
innobase_hton_name,
"Innobase OY",
- innobase_hton_comment,
- NULL, /* Plugin Init */
+ "Supports transactions, row-level locking, and foreign keys",
+ innobase_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
0
@@ -7475,3 +7462,4 @@ mysql_declare_plugin(innobase)
mysql_declare_plugin_end;
#endif
+
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 4f0c9eb151b..c7d698cbcf4 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -33,6 +33,8 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
+struct row_prebuilt_struct;
+
my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
uint full_name_len,
ulonglong *unused);
@@ -89,7 +91,7 @@ class ha_innobase: public handler
const char* table_type() const { return("InnoDB");}
const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
- ulong table_flags() const { return int_table_flags; }
+ ulonglong table_flags() const { return int_table_flags; }
ulong index_flags(uint idx, uint part, bool all_parts) const
{
return (HA_READ_NEXT |
@@ -109,7 +111,6 @@ class ha_innobase: public handler
uint max_supported_key_length() const { return 3500; }
uint max_supported_key_part_length() const;
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
- bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -147,20 +148,10 @@ class ha_innobase: public handler
int optimize(THD* thd,HA_CHECK_OPT* check_opt);
int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
+ int reset();
int external_lock(THD *thd, int lock_type);
int transactional_table_lock(THD *thd, int lock_type);
int start_stmt(THD *thd, thr_lock_type lock_type);
-
- int ha_retrieve_all_cols()
- {
- ha_set_all_bits_in_read_set();
- return extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- }
- int ha_retrieve_all_pk()
- {
- ha_set_primary_key_in_read_set();
- return extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
- }
void position(byte *record);
ha_rows records_in_range(uint inx, key_range *min_key, key_range
*max_key);
@@ -181,7 +172,10 @@ class ha_innobase: public handler
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
- ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
int reset_auto_increment(ulonglong value);
virtual bool get_error_message(int error, String *buf);
@@ -207,6 +201,8 @@ class ha_innobase: public handler
int cmp_ref(const byte *ref1, const byte *ref2);
bool check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes);
+ void build_template(struct row_prebuilt_struct *prebuilt, THD *thd,
+ TABLE *table, uint templ_type);
};
extern SHOW_VAR innodb_status_variables[];
@@ -249,7 +245,7 @@ extern ulong srv_thread_concurrency;
extern ulong srv_commit_concurrency;
}
-bool innobase_init(void);
+int innobase_init(void);
int innobase_end(ha_panic_function type);
bool innobase_flush_logs(void);
uint innobase_get_free_space(void);
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 40081c975c8..2d097c34f97 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -52,63 +52,11 @@ TYPELIB myisam_stats_method_typelib= {
** MyISAM tables
*****************************************************************************/
-static handler *myisam_create_handler(TABLE_SHARE *table);
-
-/* MyISAM handlerton */
-
-static const char myisam_hton_name[]= "MyISAM";
-static const char myisam_hton_comment[]=
- "Default engine as of MySQL 3.23 with great performance";
-
-handlerton myisam_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- myisam_hton_name,
- SHOW_OPTION_YES,
- myisam_hton_comment,
- DB_TYPE_MYISAM,
- NULL,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- /*
- MyISAM doesn't support transactions and doesn't have
- transaction-dependent context: cursors can survive a commit.
- */
- myisam_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- mi_panic,/* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill Files Table */
- HTON_CAN_RECREATE,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
-
-
-static handler *myisam_create_handler(TABLE_SHARE *table)
+static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_myisam(table);
+ return new (mem_root) ha_myisam(table);
}
-
// collect errors printed by mi_check routines
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
@@ -192,10 +140,11 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
ha_myisam::ha_myisam(TABLE_SHARE *table_arg)
:handler(&myisam_hton, table_arg), file(0),
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
- HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
- HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS),
- can_enable_indexes(1)
+ HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
+ HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
+ HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
+ HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT),
+ can_enable_indexes(1)
{}
@@ -1318,7 +1267,7 @@ int ha_myisam::rnd_init(bool scan)
{
if (scan)
return mi_scan_init(file);
- return mi_extra(file, HA_EXTRA_RESET, 0);
+ return mi_reset(file); // Free buffers
}
int ha_myisam::rnd_next(byte *buf)
@@ -1358,24 +1307,23 @@ void ha_myisam::info(uint flag)
(void) mi_status(file,&info,flag);
if (flag & HA_STATUS_VARIABLE)
{
- records = info.records;
- deleted = info.deleted;
- data_file_length=info.data_file_length;
- index_file_length=info.index_file_length;
- delete_length = info.delete_length;
- check_time = info.check_time;
- mean_rec_length=info.mean_reclength;
+ stats.records = info.records;
+ stats.deleted = info.deleted;
+ stats.data_file_length=info.data_file_length;
+ stats.index_file_length=info.index_file_length;
+ stats.delete_length = info.delete_length;
+ stats.check_time = info.check_time;
+ stats. mean_rec_length=info.mean_reclength;
}
if (flag & HA_STATUS_CONST)
{
TABLE_SHARE *share= table->s;
- max_data_file_length= info.max_data_file_length;
- max_index_file_length= info.max_index_file_length;
- create_time= info.create_time;
- sortkey= info.sortkey;
+ stats.max_data_file_length= info.max_data_file_length;
+ stats.max_index_file_length= info.max_index_file_length;
+ stats.create_time= info.create_time;
ref_length= info.reflength;
share->db_options_in_use= info.options;
- block_size= myisam_block_size; /* record block size */
+ stats.block_size= myisam_block_size; /* record block size */
/* Update share */
if (share->tmp_table == NO_TMP_TABLE)
@@ -1406,12 +1354,12 @@ void ha_myisam::info(uint flag)
if (flag & HA_STATUS_ERRKEY)
{
errkey = info.errkey;
- my_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
+ my_store_ptr(dup_ref, ref_length, info.dupp_key_pos);
}
if (flag & HA_STATUS_TIME)
- update_time = info.update_time;
+ stats.update_time = info.update_time;
if (flag & HA_STATUS_AUTO)
- auto_increment_value= info.auto_increment;
+ stats.auto_increment_value= info.auto_increment;
}
@@ -1422,6 +1370,10 @@ int ha_myisam::extra(enum ha_extra_function operation)
return mi_extra(file, operation, 0);
}
+int ha_myisam::reset(void)
+{
+ return mi_reset(file);
+}
/* To be used with WRITE_CACHE and EXTRA_CACHE */
@@ -1465,7 +1417,7 @@ void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
{
- create_info->auto_increment_value=auto_increment_value;
+ 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;
@@ -1690,7 +1642,10 @@ int ha_myisam::rename_table(const char * from, const char * to)
}
-ulonglong ha_myisam::get_auto_increment()
+void ha_myisam::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
ulonglong nr;
int error;
@@ -1699,7 +1654,10 @@ ulonglong ha_myisam::get_auto_increment()
if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
ha_myisam::info(HA_STATUS_AUTO);
- return auto_increment_value;
+ *first_value= stats.auto_increment_value;
+ /* MyISAM has only table-level lock, so reserves to +inf */
+ *nb_reserved_values= ULONGLONG_MAX;
+ return;
}
/* it's safe to call the following if bulk_insert isn't on */
@@ -1720,7 +1678,14 @@ ulonglong ha_myisam::get_auto_increment()
val_int_offset(table->s->rec_buff_length)+1);
}
extra(HA_EXTRA_NO_KEYREAD);
- return nr;
+ *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;
}
@@ -1783,7 +1748,7 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
{
uint options= table->s->db_options_in_use;
- if (info->auto_increment_value != auto_increment_value ||
+ if (info->auto_increment_value != stats.auto_increment_value ||
info->data_file_name != data_file_name ||
info->index_file_name != index_file_name ||
table_changes == IS_EQUAL_NO ||
@@ -1798,17 +1763,32 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
+handlerton myisam_hton;
+
+static int myisam_init()
+{
+ myisam_hton.state=SHOW_OPTION_YES;
+ myisam_hton.db_type=DB_TYPE_MYISAM;
+ myisam_hton.create=myisam_create_handler;
+ myisam_hton.panic=mi_panic;
+ myisam_hton.flags=HTON_CAN_RECREATE;
+ return 0;
+}
+
+struct st_mysql_storage_engine myisam_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &myisam_hton };
mysql_declare_plugin(myisam)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &myisam_hton,
- myisam_hton_name,
+ &myisam_storage_engine,
+ "MyISAM",
"MySQL AB",
- myisam_hton_comment,
- NULL, /* Plugin Init */
+ "Default engine as of MySQL 3.23 with great performance",
+ myisam_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100, /* 1.0 */
0
}
mysql_declare_plugin_end;
+
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 86efed27478..5544e5040b3 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -48,7 +48,7 @@ class ha_myisam: public handler
const char *table_type() const { return "MyISAM"; }
const char *index_type(uint key_number);
const char **bas_ext() const;
- ulong table_flags() const { return int_table_flags; }
+ 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) ?
@@ -101,6 +101,7 @@ class ha_myisam: public handler
void info(uint);
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 delete_all_rows(void);
int disable_indexes(uint mode);
@@ -113,7 +114,10 @@ class ha_myisam: public handler
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);
- ulonglong get_auto_increment();
+ 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);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index f4a052cea8a..afeed5f79df 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -34,55 +34,17 @@
** MyISAM MERGE tables
*****************************************************************************/
-static handler *myisammrg_create_handler(TABLE_SHARE *table);
+static handler *myisammrg_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
/* MyISAM MERGE handlerton */
-static const char myisammrg_hton_name[]= "MRG_MYISAM";
-static const char myisammrg_hton_comment[]=
- "Collection of identical MyISAM tables";
-
-handlerton myisammrg_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- myisammrg_hton_name,
- SHOW_OPTION_YES,
- myisammrg_hton_comment,
- DB_TYPE_MRG_MYISAM,
- NULL,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- myisammrg_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- myrg_panic, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill Files Table */
- HTON_CAN_RECREATE | HTON_ALTER_CANNOT_CREATE,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
+handlerton myisammrg_hton;
-static handler *myisammrg_create_handler(TABLE_SHARE *table)
+static handler *myisammrg_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
{
- return new ha_myisammrg(table);
+ return new (mem_root) ha_myisammrg(table);
}
@@ -134,10 +96,10 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_WAIT_LOCK,0);
- if (table->s->reclength != mean_rec_length && mean_rec_length)
+ if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length)
{
DBUG_PRINT("error",("reclength: %d mean_rec_length: %d",
- table->s->reclength, mean_rec_length));
+ table->s->reclength, stats.mean_rec_length));
goto err;
}
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
@@ -258,11 +220,13 @@ int ha_myisammrg::index_next_same(byte * buf,
return error;
}
+
int ha_myisammrg::rnd_init(bool scan)
{
- return myrg_extra(file,HA_EXTRA_RESET,0);
+ return myrg_reset(file);
}
+
int ha_myisammrg::rnd_next(byte *buf)
{
statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
@@ -272,6 +236,7 @@ int ha_myisammrg::rnd_next(byte *buf)
return error;
}
+
int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
{
statistic_increment(table->in_use->status_var.ha_read_rnd_count,
@@ -303,18 +268,18 @@ void ha_myisammrg::info(uint flag)
The following fails if one has not compiled MySQL with -DBIG_TABLES
and one has more than 2^32 rows in the merge tables.
*/
- records = (ha_rows) info.records;
- deleted = (ha_rows) info.deleted;
+ stats.records = (ha_rows) info.records;
+ stats.deleted = (ha_rows) info.deleted;
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
if ((info.records >= (ulonglong) 1 << 32) ||
(info.deleted >= (ulonglong) 1 << 32))
table->s->crashed= 1;
#endif
- data_file_length=info.data_file_length;
+ stats.data_file_length=info.data_file_length;
errkey = info.errkey;
table->s->keys_in_use.set_prefix(table->s->keys);
table->s->db_options_in_use= info.options;
- mean_rec_length= info.reclength;
+ stats.mean_rec_length= info.reclength;
/*
The handler::block_size is used all over the code in index scan cost
@@ -332,11 +297,11 @@ void ha_myisammrg::info(uint flag)
TODO: In 5.2 index scan cost calculation will be factored out into a
virtual function in class handler and we'll be able to remove this hack.
*/
- block_size= 0;
+ stats.block_size= 0;
if (file->tables)
- block_size= myisam_block_size / file->tables;
+ stats.block_size= myisam_block_size / file->tables;
- update_time=0;
+ stats.update_time= 0;
#if SIZEOF_OFF_T > 4
ref_length=6; // Should be big enough
#else
@@ -362,6 +327,10 @@ int ha_myisammrg::extra(enum ha_extra_function operation)
return myrg_extra(file,operation,0);
}
+int ha_myisammrg::reset(void)
+{
+ return myrg_reset(file);
+}
/* To be used with WRITE_CACHE, EXTRA_CACHE and BULK_INSERT_BEGIN */
@@ -580,14 +549,27 @@ bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_NO;
}
+static int myisammrg_init()
+{
+ myisammrg_hton.state=SHOW_OPTION_YES;
+ myisammrg_hton.db_type=DB_TYPE_MRG_MYISAM;
+ myisammrg_hton.create=myisammrg_create_handler;
+ myisammrg_hton.panic=myrg_panic;
+ myisammrg_hton.flags= HTON_CAN_RECREATE | HTON_ALTER_CANNOT_CREATE;
+ return 0;
+}
+
+struct st_mysql_storage_engine myisammrg_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &myisammrg_hton };
+
mysql_declare_plugin(myisammrg)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &myisammrg_hton,
- myisammrg_hton_name,
+ &myisammrg_storage_engine,
+ "MRG_MYISAM",
"MySQL AB",
- myisammrg_hton_comment,
- NULL, /* Plugin Init */
+ "Collection of identical MyISAM tables",
+ myisammrg_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100, /* 1.0 */
0
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index 4327b1c17b9..b67ec3dc204 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -33,9 +33,9 @@ class ha_myisammrg: public handler
const char *table_type() const { return "MRG_MyISAM"; }
const char **bas_ext() const;
const char *index_type(uint key_number);
- ulong table_flags() const
+ ulonglong table_flags() const
{
- return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_READ_RND_SAME |
+ return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_NO_TRANSACTIONS |
HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
HA_CAN_INSERT_DELAYED | HA_ANY_INDEX_MAY_BE_UNIQUE |
HA_NO_COPY_ON_ALTER);
@@ -50,7 +50,7 @@ class ha_myisammrg: public handler
uint max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
uint max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
double scan_time()
- { return ulonglong2double(data_file_length) / IO_SIZE + file->tables; }
+ { return ulonglong2double(stats.data_file_length) / IO_SIZE + file->tables; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -73,6 +73,7 @@ class ha_myisammrg: public handler
void position(const byte *record);
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
void info(uint);
+ int reset(void);
int extra(enum ha_extra_function operation);
int extra_opt(enum ha_extra_function operation, ulong cache_size);
int external_lock(THD *thd, int lock_type);
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 5a1d4f48c9b..8c4d6d18b9b 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -63,30 +63,18 @@ static const int max_transactions= 3; // should really be 2 but there is a trans
static uint ndbcluster_partition_flags();
static uint ndbcluster_alter_table_flags(uint flags);
-static bool ndbcluster_init(void);
+static int ndbcluster_init(void);
static int ndbcluster_end(ha_panic_function flag);
static bool ndbcluster_show_status(THD*,stat_print_fn *,enum ha_stat_type);
static int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info);
static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond);
-static const char ndbcluster_hton_name[]= "ndbcluster";
-static const char ndbcluster_hton_comment[]= "Clustered, fault-tolerant tables";
-
-handlerton ndbcluster_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- "ndbcluster",
- SHOW_OPTION_YES,
- "Clustered, fault-tolerant tables",
- DB_TYPE_NDBCLUSTER,
- ndbcluster_init,
- ~(uint)0, /* slot */
- /* below are initialized by name in ndbcluster_init() */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
+handlerton ndbcluster_hton;
-static handler *ndbcluster_create_handler(TABLE_SHARE *table)
+static handler *ndbcluster_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
{
- return new ha_ndbcluster(table);
+ return new (mem_root) ha_ndbcluster(table);
}
static uint ndbcluster_partition_flags()
@@ -106,7 +94,6 @@ static uint ndbcluster_alter_table_flags(uint flags)
}
-#define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0
#define NDB_AUTO_INCREMENT_RETRIES 10
#define ERR_PRINT(err) \
@@ -182,6 +169,8 @@ static const char * ndb_connected_host= 0;
static long ndb_connected_port= 0;
static long ndb_number_of_replicas= 0;
long ndb_number_of_storage_nodes= 0;
+long ndb_number_of_ready_storage_nodes= 0;
+long ndb_connect_count= 0;
static int update_status_variables(Ndb_cluster_connection *c)
{
@@ -190,6 +179,8 @@ static int update_status_variables(Ndb_cluster_connection *c)
ndb_connected_host= c->get_connected_host();
ndb_number_of_replicas= 0;
ndb_number_of_storage_nodes= c->no_db_nodes();
+ ndb_number_of_ready_storage_nodes= c->get_no_ready();
+ ndb_connect_count= c->get_connect_count();
return 0;
}
@@ -437,9 +428,10 @@ void ha_ndbcluster::records_update()
Ndb *ndb= get_ndb();
ndb->setDatabaseName(m_dbname);
struct Ndb_statistics stat;
- if (ndb_get_table_statistics(ndb, m_table, &stat) == 0){
- mean_rec_length= stat.row_size;
- data_file_length= stat.fragment_memory;
+ if (ndb_get_table_statistics(ndb, m_table, &stat) == 0)
+ {
+ stats.mean_rec_length= stat.row_size;
+ stats.data_file_length= stat.fragment_memory;
info->records= stat.row_count;
}
}
@@ -448,7 +440,7 @@ void ha_ndbcluster::records_update()
if (get_thd_ndb(thd)->error)
info->no_uncommitted_rows_count= 0;
}
- records= info->records+ info->no_uncommitted_rows_count;
+ stats.records= info->records+ info->no_uncommitted_rows_count;
DBUG_VOID_RETURN;
}
@@ -896,23 +888,24 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
/*
Check if any set or get of blob value in current query.
*/
+
bool ha_ndbcluster::uses_blob_value()
{
+ uint blob_fields;
+ MY_BITMAP *bitmap;
+ uint *blob_index, *blob_index_end;
if (table_share->blob_fields == 0)
return FALSE;
+
+ bitmap= m_write_op ? table->write_set : table->read_set;
+ blob_index= table_share->blob_field;
+ blob_index_end= blob_index + table_share->blob_fields;
+ do
{
- uint no_fields= table_share->fields;
- int i;
- // They always put blobs at the end..
- for (i= no_fields - 1; i >= 0; i--)
- {
- if ((m_write_op && ha_get_bit_in_write_set(i+1)) ||
- (!m_write_op && ha_get_bit_in_read_set(i+1)))
- {
- return TRUE;
- }
- }
- }
+ if (bitmap_is_set(table->write_set,
+ table->field[*blob_index]->field_index))
+ return TRUE;
+ } while (++blob_index != blob_index_end);
return FALSE;
}
@@ -1409,10 +1402,9 @@ int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type)
{
if (type >= TL_WRITE_ALLOW_WRITE)
return NdbOperation::LM_Exclusive;
- else if (uses_blob_value())
+ if (uses_blob_value())
return NdbOperation::LM_Read;
- else
- return NdbOperation::LM_CommittedRead;
+ return NdbOperation::LM_CommittedRead;
}
static const ulong index_type_flags[]=
@@ -1587,13 +1579,13 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
for (i= 0; i < table_share->fields; i++)
{
Field *field= table->field[i];
- if (ha_get_bit_in_read_set(i+1) ||
+ if (bitmap_is_set(table->read_set, i) ||
((field->flags & PRI_KEY_FLAG)))
{
if (get_ndb_value(op, field, i, buf))
ERR_RETURN(op->getNdbError());
}
- else
+ else
{
m_value[i].ptr= NULL;
}
@@ -1697,7 +1689,7 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
DBUG_ENTER("complemented_read");
m_write_op= FALSE;
- if (ha_get_all_bit_in_read_set())
+ if (bitmap_is_set_all(table->read_set))
{
// We have allready retrieved all fields, nothing to complement
DBUG_RETURN(0);
@@ -1728,7 +1720,8 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
{
Field *field= table->field[i];
if (!((field->flags & PRI_KEY_FLAG) ||
- (ha_get_bit_in_read_set(i+1))))
+ bitmap_is_set(table->read_set, i)) &&
+ !bitmap_is_set(table->write_set, i))
{
if (get_ndb_value(op, field, i, new_data))
ERR_RETURN(trans->getNdbError());
@@ -1752,7 +1745,7 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
{
Field *field= table->field[i];
if (!((field->flags & PRI_KEY_FLAG) ||
- (ha_get_bit_in_read_set(i+1))))
+ bitmap_is_set(table->read_set, i)))
{
m_value[i].ptr= NULL;
}
@@ -1853,11 +1846,11 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record)
uint32 part_id;
int error;
longlong func_value;
- if ((error= m_part_info->get_partition_id(m_part_info, &part_id,
- &func_value)))
- {
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+ if (error)
DBUG_RETURN(error);
- }
op->setPartitionId(part_id);
}
}
@@ -2449,11 +2442,11 @@ int ha_ndbcluster::write_row(byte *record)
{
uint32 part_id;
int error;
- if ((error= m_part_info->get_partition_id(m_part_info, &part_id,
- &func_value)))
- {
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+ if (error)
DBUG_RETURN(error);
- }
op->setPartitionId(part_id);
}
@@ -2461,39 +2454,43 @@ int ha_ndbcluster::write_row(byte *record)
{
// Table has hidden primary key
Ndb *ndb= get_ndb();
- Uint64 auto_value= NDB_FAILED_AUTO_INCREMENT;
+ int ret;
+ Uint64 auto_value;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
do {
- auto_value= ndb->getAutoIncrementValue(m_table);
- } while (auto_value == NDB_FAILED_AUTO_INCREMENT &&
+ Ndb_tuple_id_range_guard g(m_share);
+ ret= ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1);
+ } while (ret == -1 &&
--retries &&
ndb->getNdbError().status == NdbError::TemporaryError);
- if (auto_value == NDB_FAILED_AUTO_INCREMENT)
+ if (ret == -1)
ERR_RETURN(ndb->getNdbError());
if (set_hidden_key(op, table_share->fields, (const byte*)&auto_value))
ERR_RETURN(op->getNdbError());
}
else
{
- int res;
-
- if ((res= set_primary_key_from_record(op, record)))
- return res;
+ int error;
+ if ((error= set_primary_key_from_record(op, record)))
+ DBUG_RETURN(error);
}
// Set non-key attribute(s)
bool set_blob_value= FALSE;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
for (i= 0; i < table_share->fields; i++)
{
Field *field= table->field[i];
if (!(field->flags & PRI_KEY_FLAG) &&
- (ha_get_bit_in_write_set(i + 1) || !m_use_write) &&
+ (bitmap_is_set(table->write_set, i) || !m_use_write) &&
set_ndb_value(op, field, i, record-table->record[0], &set_blob_value))
{
m_skip_auto_increment= TRUE;
+ dbug_tmp_restore_column_map(table->read_set, old_map);
ERR_RETURN(op->getNdbError());
}
}
+ dbug_tmp_restore_column_map(table->read_set, old_map);
if (m_use_partition_function)
{
@@ -2563,14 +2560,16 @@ int ha_ndbcluster::write_row(byte *record)
Ndb *ndb= get_ndb();
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
DBUG_PRINT("info",
- ("Trying to set next auto increment value to %lu",
- (ulong) next_val));
- if (ndb->setAutoIncrementValue(m_table, next_val, TRUE))
- DBUG_PRINT("info",
- ("Setting next auto increment value to %u", next_val));
+ ("Trying to set next auto increment value to %llu",
+ (ulonglong) next_val));
+ Ndb_tuple_id_range_guard g(m_share);
+ if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE)
+ == -1)
+ ERR_RETURN(ndb->getNdbError());
}
m_skip_auto_increment= TRUE;
+ DBUG_PRINT("exit",("ok"));
DBUG_RETURN(0);
}
@@ -2630,7 +2629,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
{
table->timestamp_field->set_time();
- ha_set_bit_in_write_set(table->timestamp_field->fieldnr);
+ bitmap_set_bit(table->write_set, table->timestamp_field->field_index);
}
if (m_use_partition_function &&
@@ -2744,14 +2743,19 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
m_rows_changed++;
// Set non-key attribute(s)
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
for (i= 0; i < table_share->fields; i++)
{
Field *field= table->field[i];
- if (ha_get_bit_in_write_set(i+1) &&
+ if (bitmap_is_set(table->write_set, i) &&
(!(field->flags & PRI_KEY_FLAG)) &&
set_ndb_value(op, field, i, new_data - table->record[0]))
+ {
+ dbug_tmp_restore_column_map(table->read_set, old_map);
ERR_RETURN(op->getNdbError());
+ }
}
+ dbug_tmp_restore_column_map(table->read_set, old_map);
if (m_use_partition_function)
{
@@ -2843,9 +2847,8 @@ int ha_ndbcluster::delete_row(const byte *record)
}
else
{
- int res;
- if ((res= set_primary_key_from_record(op, record)))
- return res;
+ if ((error= set_primary_key_from_record(op, record)))
+ DBUG_RETURN(error);
}
}
@@ -2875,7 +2878,8 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
MY_BITMAP *defined, byte *buf)
{
Field **p_field= table->field, *field= *p_field;
- my_ptrdiff_t row_offset= buf - table->record[0];
+ my_ptrdiff_t row_offset= (my_ptrdiff_t) (buf - table->record[0]);
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
DBUG_ENTER("ndb_unpack_record");
// Set null flag(s)
@@ -2936,13 +2940,13 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
field_bit->Field_bit::move_field_offset(-row_offset);
DBUG_PRINT("info",("[%u] SET",
(*value).rec->getColumn()->getColumnNo()));
- DBUG_DUMP("info", (const char*) field->ptr, field->field_length);
+ DBUG_DUMP("info", (const char*) field->ptr, field->pack_length());
}
else
{
DBUG_PRINT("info",("[%u] SET",
(*value).rec->getColumn()->getColumnNo()));
- DBUG_DUMP("info", (const char*) field->ptr, field->field_length);
+ DBUG_DUMP("info", (const char*) field->ptr, field->pack_length());
}
}
else
@@ -2975,6 +2979,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
}
}
}
+ dbug_tmp_restore_column_map(table->write_set, old_map);
DBUG_VOID_RETURN;
}
@@ -3497,7 +3502,7 @@ void ha_ndbcluster::info(uint flag)
if (m_table_info)
{
if (m_ha_not_exact_count)
- records= 100;
+ stats.records= 100;
else
records_update();
}
@@ -3511,14 +3516,14 @@ void ha_ndbcluster::info(uint flag)
if (current_thd->variables.ndb_use_exact_count &&
ndb_get_table_statistics(ndb, m_table, &stat) == 0)
{
- mean_rec_length= stat.row_size;
- data_file_length= stat.fragment_memory;
- records= stat.row_count;
+ stats.mean_rec_length= stat.row_size;
+ stats.data_file_length= stat.fragment_memory;
+ stats.records= stat.row_count;
}
else
{
- mean_rec_length= 0;
- records= 100;
+ stats.mean_rec_length= 0;
+ stats.records= 100;
}
}
}
@@ -3538,9 +3543,19 @@ void ha_ndbcluster::info(uint flag)
if (m_table)
{
Ndb *ndb= get_ndb();
+ Ndb_tuple_id_range_guard g(m_share);
- auto_increment_value=
- ndb->readAutoIncrementValue(m_table);
+ Uint64 auto_increment_value64;
+ if (ndb->readAutoIncrementValue(m_table, g.range,
+ auto_increment_value64) == -1)
+ {
+ const NdbError err= ndb->getNdbError();
+ sql_print_error("Error %lu in readAutoIncrementValue(): %s",
+ (ulong) err.code, err.message);
+ stats.auto_increment_value= ~(ulonglong)0;
+ }
+ else
+ stats.auto_increment_value= (ulonglong)auto_increment_value64;
}
}
DBUG_VOID_RETURN;
@@ -3564,18 +3579,6 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
{
DBUG_ENTER("extra");
switch (operation) {
- case HA_EXTRA_RESET: /* Reset database to after open */
- DBUG_PRINT("info", ("HA_EXTRA_RESET"));
- DBUG_PRINT("info", ("Clearing condition stack"));
- cond_clear();
- /*
- * Regular partition pruning will set the bitmap appropriately.
- * Some queries like ALTER TABLE doesn't use partition pruning and
- * thus the 'used_partitions' bitmap needs to be initialized
- */
- if (m_part_info)
- bitmap_set_all(&m_part_info->used_partitions);
- break;
case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
if (current_thd->lex->sql_command == SQLCOM_REPLACE && !m_has_unique_index)
@@ -3611,6 +3614,22 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
DBUG_RETURN(0);
}
+
+int ha_ndbcluster::reset()
+{
+ DBUG_ENTER("ha_ndbcluster::reset");
+ cond_clear();
+ /*
+ Regular partition pruning will set the bitmap appropriately.
+ Some queries like ALTER TABLE doesn't use partition pruning and
+ thus the 'used_partitions' bitmap needs to be initialized
+ */
+ if (m_part_info)
+ bitmap_set_all(&m_part_info->used_partitions);
+ DBUG_RETURN(0);
+}
+
+
/*
Start of an insert, remember number of rows to be inserted, it will
be used in write_row and get_autoincrement to send an optimal number
@@ -3727,7 +3746,7 @@ const char** ha_ndbcluster::bas_ext() const
double ha_ndbcluster::scan_time()
{
DBUG_ENTER("ha_ndbcluster::scan_time()");
- double res= rows2double(records*1000);
+ double res= rows2double(stats.records*1000);
DBUG_PRINT("exit", ("table: %s value: %f",
m_tabname, res));
DBUG_RETURN(res);
@@ -3811,8 +3830,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
int error=0;
NdbTransaction* trans= NULL;
-
DBUG_ENTER("external_lock");
+
/*
Check that this handler instance has a connection
set up to the Ndb object of thd
@@ -3823,9 +3842,10 @@ 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: %x thd: %lx thd_ndb: %lx "
+ DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: %lx "
"thd_ndb->lock_count: %d",
- this, thd, thd_ndb, thd_ndb->lock_count));
+ (long) this, (long) thd, (long) thd_ndb,
+ thd_ndb->lock_count));
if (lock_type != F_UNLCK)
{
@@ -4645,7 +4665,7 @@ int ha_ndbcluster::create(const char *name,
share->db, share->table_name,
m_table->getObjectId(),
m_table->getObjectVersion(),
- SOT_CREATE_TABLE);
+ SOT_CREATE_TABLE, 0, 0, 1);
break;
}
}
@@ -4918,13 +4938,17 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
{
NDBDICT *dict;
char old_dbname[FN_HEADLEN];
+ char new_dbname[FN_HEADLEN];
char new_tabname[FN_HEADLEN];
const NDBTAB *orig_tab;
int result;
+ bool recreate_indexes= FALSE;
+ NDBDICT::List index_list;
DBUG_ENTER("ha_ndbcluster::rename_table");
DBUG_PRINT("info", ("Renaming %s to %s", from, to));
set_dbname(from, old_dbname);
+ set_dbname(to, new_dbname);
set_tabname(from);
set_tabname(to, new_tabname);
@@ -4949,6 +4973,11 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
DBUG_ASSERT(r == 0);
}
#endif
+ if (my_strcasecmp(system_charset_info, new_dbname, old_dbname))
+ {
+ dict->listIndexes(index_list, *orig_tab);
+ recreate_indexes= TRUE;
+ }
// Change current database to that of target table
set_dbname(to);
ndb->setDatabaseName(m_dbname);
@@ -5027,7 +5056,33 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
old_dbname, m_tabname,
ndb_table_id, ndb_table_version,
SOT_RENAME_TABLE,
- m_dbname, new_tabname);
+ m_dbname, new_tabname, 1);
+ }
+
+ // If we are moving tables between databases, we need to recreate
+ // indexes
+ if (recreate_indexes)
+ {
+ for (unsigned i = 0; i < index_list.count; i++)
+ {
+ NDBDICT::List::Element& index_el = index_list.elements[i];
+ // Recreate any indexes not stored in the system database
+ if (my_strcasecmp(system_charset_info,
+ index_el.database, NDB_SYSTEM_DATABASE))
+ {
+ set_dbname(from);
+ ndb->setDatabaseName(m_dbname);
+ const NDBINDEX * index= dict->getIndexGlobal(index_el.name, new_tab);
+ DBUG_PRINT("info", ("Creating index %s/%s",
+ index_el.database, index->getName()));
+ dict->createIndex(*index, new_tab);
+ DBUG_PRINT("info", ("Dropping index %s/%s",
+ index_el.database, index->getName()));
+ set_dbname(from);
+ ndb->setDatabaseName(m_dbname);
+ dict->dropIndexGlobal(*index);
+ }
+ }
}
if (share)
free_share(&share);
@@ -5050,6 +5105,7 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
const char *db,
const char *table_name)
{
+ THD *thd= current_thd;
DBUG_ENTER("ha_ndbcluster::ndbcluster_delete_table");
NDBDICT *dict= ndb->getDictionary();
#ifdef HAVE_NDB_BINLOG
@@ -5069,7 +5125,7 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
/* Drop the table from NDB */
- int res;
+ int res= 0;
if (h && h->m_table)
{
if (dict->dropTableGlobal(*h->m_table))
@@ -5081,7 +5137,7 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
ndb_table_version= h->m_table->getObjectVersion();
}
#endif
- h->release_metadata(current_thd, ndb);
+ h->release_metadata(thd, ndb);
}
else
{
@@ -5097,7 +5153,6 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
ndb_table_id= ndbtab_g.get_table()->getObjectId();
ndb_table_version= ndbtab_g.get_table()->getObjectVersion();
#endif
- res= 0;
}
else if (dict->getNdbError().code == NDB_INVALID_SCHEMA_OBJECT)
{
@@ -5147,11 +5202,11 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
if (!IS_TMP_PREFIX(table_name) && share)
{
- ndbcluster_log_schema_op(current_thd, share,
- current_thd->query, current_thd->query_length,
+ ndbcluster_log_schema_op(thd, share,
+ thd->query, thd->query_length,
share->db, share->table_name,
ndb_table_id, ndb_table_version,
- SOT_DROP_TABLE);
+ SOT_DROP_TABLE, 0, 0, 1);
}
else if (table_dropped && share && share->op) /* ndbcluster_log_schema_op
will do a force GCP */
@@ -5214,7 +5269,10 @@ int ha_ndbcluster::delete_table(const char *name)
}
-ulonglong ha_ndbcluster::get_auto_increment()
+void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
int cache_size;
Uint64 auto_value;
@@ -5232,24 +5290,29 @@ ulonglong ha_ndbcluster::get_auto_increment()
m_rows_to_insert - m_rows_inserted :
((m_rows_to_insert > m_autoincrement_prefetch) ?
m_rows_to_insert : m_autoincrement_prefetch));
- auto_value= NDB_FAILED_AUTO_INCREMENT;
+ int ret;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
do {
- auto_value=
- (m_skip_auto_increment) ?
- ndb->readAutoIncrementValue(m_table)
- : ndb->getAutoIncrementValue(m_table, cache_size);
- } while (auto_value == NDB_FAILED_AUTO_INCREMENT &&
+ Ndb_tuple_id_range_guard g(m_share);
+ ret=
+ m_skip_auto_increment ?
+ ndb->readAutoIncrementValue(m_table, g.range, auto_value) :
+ ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size);
+ } while (ret == -1 &&
--retries &&
ndb->getNdbError().status == NdbError::TemporaryError);
- if (auto_value == NDB_FAILED_AUTO_INCREMENT)
+ if (ret == -1)
{
const NdbError err= ndb->getNdbError();
sql_print_error("Error %lu in ::get_auto_increment(): %s",
(ulong) err.code, err.message);
- DBUG_RETURN(~(ulonglong) 0);
+ *first_value= ~(ulonglong) 0;
+ DBUG_VOID_RETURN;
}
- DBUG_RETURN((longlong)auto_value);
+ *first_value= (longlong)auto_value;
+ /* From the point of view of MySQL, NDB reserves one row at a time */
+ *nb_reserved_values= 1;
+ DBUG_VOID_RETURN;
}
@@ -5265,7 +5328,9 @@ ulonglong ha_ndbcluster::get_auto_increment()
HA_NEED_READ_RANGE_BUFFER | \
HA_CAN_GEOMETRY | \
HA_CAN_BIT_FIELD | \
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
+ HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | \
+ HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | \
+ HA_PARTIAL_COLUMN_READ
ha_ndbcluster::ha_ndbcluster(TABLE_SHARE *table_arg):
handler(&ndbcluster_hton, table_arg),
@@ -5308,8 +5373,8 @@ ha_ndbcluster::ha_ndbcluster(TABLE_SHARE *table_arg):
m_tabname[0]= '\0';
m_dbname[0]= '\0';
- records= ~(ha_rows)0; // uninitialized
- block_size= 1024;
+ stats.records= ~(ha_rows)0; // uninitialized
+ stats.block_size= 1024;
for (i= 0; i < MAX_KEY; i++)
ndb_init_index(m_index[i]);
@@ -5633,7 +5698,7 @@ int ndbcluster_table_exists_in_engine(THD* thd, const char *db,
{
Ndb* ndb;
DBUG_ENTER("ndbcluster_table_exists_in_engine");
- DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
+ DBUG_PRINT("enter", ("db: %s name: %s", db, name));
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
@@ -5642,14 +5707,13 @@ int ndbcluster_table_exists_in_engine(THD* thd, const char *db,
NdbDictionary::Dictionary::List list;
if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
ERR_RETURN(dict->getNdbError());
- for (int i= 0 ; i < list.count ; i++)
+ for (uint i= 0 ; i < list.count ; i++)
{
NdbDictionary::Dictionary::List::Element& elmt= list.elements[i];
if (my_strcasecmp(system_charset_info, elmt.database, db))
continue;
if (my_strcasecmp(system_charset_info, elmt.name, name))
continue;
- // table found
DBUG_PRINT("info", ("Found table"));
DBUG_RETURN(1);
}
@@ -5729,6 +5793,7 @@ int ndbcluster_drop_database_impl(const char *path)
static void ndbcluster_drop_database(char *path)
{
+ THD *thd= current_thd;
DBUG_ENTER("ndbcluster_drop_database");
#ifdef HAVE_NDB_BINLOG
/*
@@ -5746,9 +5811,9 @@ static void ndbcluster_drop_database(char *path)
#ifdef HAVE_NDB_BINLOG
char db[FN_REFLEN];
ha_ndbcluster::set_dbname(path, db);
- ndbcluster_log_schema_op(current_thd, 0,
- current_thd->query, current_thd->query_length,
- db, "", 0, 0, SOT_DROP_DB);
+ ndbcluster_log_schema_op(thd, 0,
+ thd->query, thd->query_length,
+ db, "", 0, 0, SOT_DROP_DB, 0, 0, 0);
#endif
DBUG_VOID_RETURN;
}
@@ -5779,6 +5844,8 @@ int ndbcluster_find_all_files(THD *thd)
NDBDICT *dict= ndb->getDictionary();
int unhandled, retries= 5, skipped;
+ LINT_INIT(unhandled);
+ LINT_INIT(skipped);
do
{
NdbDictionary::Dictionary::List list;
@@ -6090,17 +6157,18 @@ static int connect_callback()
}
extern int ndb_dictionary_is_mysqld;
-static bool ndbcluster_init()
+
+static int ndbcluster_init()
{
int res;
DBUG_ENTER("ndbcluster_init");
ndb_dictionary_is_mysqld= 1;
- if (have_ndbcluster != SHOW_OPTION_YES)
- goto ndbcluster_init_error;
{
handlerton &h= ndbcluster_hton;
+ h.state= have_ndbcluster;
+ h.db_type= DB_TYPE_NDBCLUSTER;
h.close_connection= ndbcluster_close_connection;
h.commit= ndbcluster_commit;
h.rollback= ndbcluster_rollback;
@@ -6118,6 +6186,9 @@ static bool ndbcluster_init()
h.flags= HTON_TEMPORARY_NOT_SUPPORTED;
}
+ if (have_ndbcluster != SHOW_OPTION_YES)
+ DBUG_RETURN(0); // nothing else to do
+
// Set connectstring if specified
if (opt_ndbcluster_connectstring != 0)
DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring));
@@ -6189,7 +6260,7 @@ static bool ndbcluster_init()
if (ndbcluster_binlog_start())
goto ndbcluster_init_error;
#endif /* HAVE_NDB_BINLOG */
-
+
pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_ndb_util_thread, NULL);
@@ -6205,7 +6276,7 @@ static bool ndbcluster_init()
pthread_cond_destroy(&COND_ndb_util_thread);
goto ndbcluster_init_error;
}
-
+
ndbcluster_inited= 1;
DBUG_RETURN(FALSE);
@@ -6281,9 +6352,11 @@ void ha_ndbcluster::print_error(int error, myf errflag)
if (error == HA_ERR_NO_PARTITION_FOUND)
{
char buf[100];
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0),
m_part_info->part_expr->null_value ? "NULL" :
llstr(m_part_info->part_expr->val_int(), buf));
+ dbug_tmp_restore_column_map(table->read_set, old_map);
}
else
handler::print_error(error, errflag);
@@ -6501,12 +6574,11 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
DBUG_RETURN(10); /* Good guess when you don't know anything */
}
-ulong ha_ndbcluster::table_flags(void) const
+ulonglong ha_ndbcluster::table_flags(void) const
{
if (m_ha_not_exact_count)
- return m_table_flags | HA_NOT_EXACT_COUNT;
- else
- return m_table_flags;
+ return m_table_flags & ~HA_STATS_RECORDS_IS_EXACT;
+ return m_table_flags;
}
const char * ha_ndbcluster::table_type() const
{
@@ -6540,10 +6612,6 @@ bool ha_ndbcluster::low_byte_first() const
return TRUE;
#endif
}
-bool ha_ndbcluster::has_transactions()
-{
- return TRUE;
-}
const char* ha_ndbcluster::index_type(uint key_number)
{
switch (get_index_type(key_number)) {
@@ -6823,6 +6891,7 @@ static void dbug_print_open_tables()
*/
int handle_trailing_share(NDB_SHARE *share)
{
+ THD *thd= current_thd;
static ulong trailing_share_id= 0;
DBUG_ENTER("handle_trailing_share");
@@ -6833,7 +6902,7 @@ int handle_trailing_share(NDB_SHARE *share)
bzero((char*) &table_list,sizeof(table_list));
table_list.db= share->db;
table_list.alias= table_list.table_name= share->table_name;
- close_cached_tables(current_thd, 0, &table_list, TRUE);
+ close_cached_tables(thd, 0, &table_list, TRUE);
pthread_mutex_lock(&ndbcluster_mutex);
if (!--share->use_count)
@@ -7128,10 +7197,6 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
#ifndef DBUG_OFF
bzero((gptr)(*share)->table_share, sizeof(*(*share)->table_share));
bzero((gptr)(*share)->table, sizeof(*(*share)->table));
-#endif
- my_free((gptr) (*share)->table_share, MYF(0));
- my_free((gptr) (*share)->table, MYF(0));
-#ifndef DBUG_OFF
(*share)->table_share= 0;
(*share)->table= 0;
#endif
@@ -9361,14 +9426,17 @@ ndbcluster_show_status(THD* thd, stat_print_fn *stat_print,
"cluster_node_id=%u, "
"connected_host=%s, "
"connected_port=%u, "
- "number_of_storage_nodes=%u",
+ "number_of_storage_nodes=%u, "
+ "number_of_ready_storage_nodes=%u, "
+ "connect_count=%u",
ndb_cluster_node_id,
ndb_connected_host,
ndb_connected_port,
- ndb_number_of_storage_nodes);
- if (stat_print(thd, ndbcluster_hton.name, strlen(ndbcluster_hton.name),
- "connection", strlen("connection"),
- buf, buflen))
+ ndb_number_of_storage_nodes,
+ ndb_number_of_ready_storage_nodes,
+ ndb_connect_count);
+ if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
+ STRING_WITH_LEN("connection"), buf, buflen))
DBUG_RETURN(TRUE);
if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb)
@@ -9382,7 +9450,7 @@ ndbcluster_show_status(THD* thd, stat_print_fn *stat_print,
my_snprintf(buf, sizeof(buf),
"created=%u, free=%u, sizeof=%u",
tmp.m_created, tmp.m_free, tmp.m_sizeof);
- if (stat_print(thd, ndbcluster_hton.name, strlen(ndbcluster_hton.name),
+ if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
tmp.m_name, strlen(tmp.m_name), buf, buflen))
DBUG_RETURN(TRUE);
}
@@ -9598,7 +9666,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
for (i= 0; i < part_info->part_field_list.elements; i++)
{
- NDBCOL *col= tab->getColumn(fields[i]->fieldnr - 1);
+ NDBCOL *col= tab->getColumn(fields[i]->field_index);
DBUG_PRINT("info",("setting dist key on %s", col->getName()));
col->setPartitionKey(TRUE);
}
@@ -9688,7 +9756,7 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
{
Field *field= table->field[i];
const NDBCOL *col= tab->getColumn(field->field_name);
- if (field->add_index &&
+ if ((field->flags & FIELD_IN_ADD_INDEX) &&
col->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
{
DBUG_PRINT("info", ("add/drop index not supported for disk stored column"));
@@ -9937,13 +10005,13 @@ int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info)
thd->query, thd->query_length,
"", info->tablespace_name,
0, 0,
- SOT_TABLESPACE);
+ SOT_TABLESPACE, 0, 0, 0);
else
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
"", info->logfile_group_name,
0, 0,
- SOT_LOGFILE_GROUP);
+ SOT_LOGFILE_GROUP, 0, 0, 0);
#endif
DBUG_RETURN(FALSE);
@@ -9964,10 +10032,11 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
const NDBTAB *tab;
int err;
DBUG_ENTER("ha_ndbcluster::get_no_parts");
+ LINT_INIT(err);
set_dbname(name);
set_tabname(name);
- do
+ for (;;)
{
if (check_ndb_connection())
{
@@ -9981,22 +10050,21 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
ERR_BREAK(dict->getNdbError(), err);
*no_parts= ndbtab_g.get_table()->getFragmentCount();
DBUG_RETURN(FALSE);
- } while (1);
+ }
-end:
print_error(err, MYF(0));
DBUG_RETURN(TRUE);
}
-static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
+static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables,
+ COND *cond)
{
TABLE* table= tables->table;
Ndb *ndb= check_ndb_in_thd(thd);
NdbDictionary::Dictionary* dict= ndb->getDictionary();
NdbDictionary::Dictionary::List dflist;
NdbError ndberr;
- unsigned i;
-
+ uint i;
DBUG_ENTER("ndbcluster_fill_files_table");
dict->listObjects(dflist, NdbDictionary::Object::Datafile);
@@ -10008,12 +10076,13 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
{
NdbDictionary::Dictionary::List::Element& elt = dflist.elements[i];
Ndb_cluster_connection_node_iter iter;
- unsigned id;
-
+ uint id;
+
g_ndb_cluster_connection->init_get_next_node(iter);
while ((id= g_ndb_cluster_connection->get_next_node(iter)))
{
+ uint c= 0;
NdbDictionary::Datafile df= dict->getDatafile(id, elt.name);
ndberr= dict->getNdbError();
if(ndberr.classification != NdbError::NoError)
@@ -10031,7 +10100,6 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
ERR_RETURN(ndberr);
}
- int c= 0;
table->field[c++]->set_null(); // FILE_ID
table->field[c++]->store(elt.name, strlen(elt.name),
system_charset_info);
@@ -10047,8 +10115,8 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
strlen(ts.getDefaultLogfileGroup()),
system_charset_info);
table->field[c++]->set_null(); // LOGFILE_GROUP_NUMBER
- table->field[c++]->store(ndbcluster_hton.name,
- strlen(ndbcluster_hton.name),
+ table->field[c++]->store(ndbcluster_hton_name,
+ ndbcluster_hton_name_length,
system_charset_info); // ENGINE
table->field[c++]->set_null(); // FULLTEXT_KEYS
@@ -10141,8 +10209,8 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
strlen(uf.getLogfileGroup()),
system_charset_info);
table->field[c++]->store(uf.getLogfileGroupId()); // LOGFILE_GROUP_NUMBER
- table->field[c++]->store(ndbcluster_hton.name,
- strlen(ndbcluster_hton.name),
+ table->field[c++]->store(ndbcluster_hton_name,
+ ndbcluster_hton_name_length,
system_charset_info); // ENGINE
table->field[c++]->set_null(); // FULLTEXT_KEYS
@@ -10188,15 +10256,17 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(0);
}
+struct st_mysql_storage_engine ndbcluster_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &ndbcluster_hton };
mysql_declare_plugin(ndbcluster)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &ndbcluster_hton,
+ &ndbcluster_storage_engine,
ndbcluster_hton_name,
"MySQL AB",
- ndbcluster_hton_comment,
- NULL, /* Plugin Init */
+ "Clustered, fault-tolerant tables",
+ ndbcluster_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
0
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index f407cb0090f..a5215ee3a04 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -106,6 +106,7 @@ typedef struct st_ndbcluster_share {
ulonglong commit_count;
char *db;
char *table_name;
+ Ndb::TupleIdRange tuple_id_range;
#ifdef HAVE_NDB_BINLOG
uint32 flags;
NdbEventOperation *op;
@@ -113,6 +114,7 @@ typedef struct st_ndbcluster_share {
char *old_names; // for rename table
TABLE_SHARE *table_share;
TABLE *table;
+ byte *record[2]; // pointer to allocated records for receiving data
NdbValue *ndb_value[2];
MY_BITMAP *subscriber_bitmap;
#endif
@@ -138,6 +140,19 @@ set_ndb_share_state(NDB_SHARE *share, NDB_SHARE_STATE state)
pthread_mutex_unlock(&share->mutex);
}
+struct Ndb_tuple_id_range_guard {
+ Ndb_tuple_id_range_guard(NDB_SHARE* _share) :
+ share(_share),
+ range(share->tuple_id_range) {
+ pthread_mutex_lock(&share->mutex);
+ }
+ ~Ndb_tuple_id_range_guard() {
+ pthread_mutex_unlock(&share->mutex);
+ }
+ NDB_SHARE* share;
+ Ndb::TupleIdRange& range;
+};
+
#ifdef HAVE_NDB_BINLOG
/* NDB_SHARE.flags */
#define NSF_HIDDEN_PK 1 /* table has hidden primary key */
@@ -335,7 +350,12 @@ class Ndb_item {
const Item *item= value.item;
if (item && field)
- ((Item *)item)->save_in_field(field, false);
+ {
+ my_bitmap_map *old_map=
+ dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ ((Item *)item)->save_in_field(field, FALSE);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
+ }
};
static NDB_FUNC_TYPE item_func_to_ndb_func(Item_func::Functype fun)
@@ -606,12 +626,13 @@ class ha_ndbcluster: public handler
void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id);
int extra(enum ha_extra_function operation);
int extra_opt(enum ha_extra_function operation, ulong cache_size);
+ int reset();
int external_lock(THD *thd, int lock_type);
int start_stmt(THD *thd, thr_lock_type lock_type);
void print_error(int error, myf errflag);
const char * table_type() const;
const char ** bas_ext() const;
- ulong table_flags(void) const;
+ ulonglong table_flags(void) const;
void prepare_for_alter();
int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
int prepare_drop_index(TABLE *table_arg, uint *key_num, uint num_of_keys);
@@ -638,7 +659,6 @@ class ha_ndbcluster: public handler
enum thr_lock_type lock_type);
bool low_byte_first() const;
- bool has_transactions();
virtual bool is_injective() const { return true; }
@@ -676,7 +696,7 @@ static void set_tabname(const char *pathname, char *tabname);
AND ... AND pushed_condN)
or less restrictive condition, depending on handler's capabilities.
- handler->extra(HA_EXTRA_RESET) call empties the condition stack.
+ handler->reset() call empties the condition stack.
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
condition stack.
The current implementation supports arbitrary AND/OR nested conditions
@@ -725,7 +745,6 @@ private:
int drop_indexes(Ndb *ndb, TABLE *tab);
int add_index_handle(THD *thd, NdbDictionary::Dictionary *dict,
KEY *key_info, const char *index_name, uint index_no);
- int initialize_autoincrement(const void *table);
int get_metadata(const char* path);
void release_metadata(THD *thd, Ndb *ndb);
NDB_INDEX_TYPE get_index_type(uint idx_no) const;
@@ -789,7 +808,10 @@ private:
int set_index_key(NdbOperation *, const KEY *key_info, const byte *key_ptr);
void print_results();
- ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
int ndb_err(NdbTransaction*);
bool uses_blob_value();
@@ -851,7 +873,7 @@ private:
bool m_primary_key_update;
bool m_write_op;
bool m_ignore_no_key;
- ha_rows m_rows_to_insert;
+ ha_rows m_rows_to_insert; // TODO: merge it with handler::estimation_rows_to_insert?
ha_rows m_rows_inserted;
ha_rows m_bulk_insert_rows;
ha_rows m_rows_changed;
@@ -889,3 +911,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
int ndbcluster_table_exists_in_engine(THD* thd,
const char *db, const char *name);
void ndbcluster_print_error(int error, const NdbOperation *error_op);
+
+static const char ndbcluster_hton_name[]= "ndbcluster";
+static const int ndbcluster_hton_name_length=sizeof(ndbcluster_hton_name)-1;
+
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index bae2a3cbd9f..3b93eb4b4c9 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -25,6 +25,7 @@
#include "slave.h"
#include "ha_ndbcluster_binlog.h"
#include "NdbDictionary.hpp"
+#include <util/NdbAutoPtr.hpp>
#ifdef ndb_dynamite
#undef assert
@@ -39,6 +40,12 @@
#define NDB_SCHEMA_TABLE_FILE "./" NDB_REP_DB "/" NDB_SCHEMA_TABLE
/*
+ Timeout for syncing schema events between
+ mysql servers, and between mysql server and the binlog
+*/
+const int opt_ndb_sync_timeout= 120;
+
+/*
Flag showing if the ndb injector thread is running, if so == 1
-1 if it was started but later stopped for some reason
0 if never started
@@ -263,9 +270,18 @@ ndbcluster_binlog_close_table(THD *thd, NDB_SHARE *share)
DBUG_VOID_RETURN;
}
+
+/*
+ Creates a TABLE object for the ndb cluster table
+
+ NOTES
+ This does not open the underlying table
+*/
+
static int
ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
- TABLE_SHARE *table_share, TABLE *table)
+ TABLE_SHARE *table_share, TABLE *table,
+ int reopen)
{
int error;
DBUG_ENTER("ndbcluster_binlog_open_table");
@@ -278,27 +294,34 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
share->key, error);
DBUG_PRINT("error", ("open_table_def failed %d", error));
free_table_share(table_share);
- my_free((gptr) table_share, MYF(0));
- my_free((gptr) table, MYF(0));
DBUG_RETURN(error);
}
- if ((error= open_table_from_share(thd, table_share, "", 0,
+ if ((error= open_table_from_share(thd, table_share, "", 0 /* fon't allocate buffers */,
(uint) READ_ALL, 0, table, FALSE)))
{
sql_print_error("Unable to open table for %s, error=%d(%d)",
share->key, error, my_errno);
DBUG_PRINT("error", ("open_table_from_share failed %d", error));
free_table_share(table_share);
- my_free((gptr) table_share, MYF(0));
- my_free((gptr) table, MYF(0));
DBUG_RETURN(error);
}
assign_new_table_id(table_share);
- if (!table->record[1] || table->record[1] == table->record[0])
+
+ if (!reopen)
+ {
+ // allocate memory on ndb share so it can be reused after online alter table
+ share->record[0]= (byte*) alloc_root(&share->mem_root, table->s->rec_buff_length);
+ share->record[1]= (byte*) alloc_root(&share->mem_root, table->s->rec_buff_length);
+ }
{
- table->record[1]= alloc_root(&table->mem_root,
- table->s->rec_buff_length);
+ my_ptrdiff_t row_offset= share->record[0] - table->record[0];
+ Field **p_field;
+ for (p_field= table->field; *p_field; p_field++)
+ (*p_field)->move_field_offset(row_offset);
+ table->record[0]= share->record[0];
+ table->record[1]= share->record[1];
}
+
table->in_use= injector_thd;
table->s->db.str= share->db;
@@ -310,6 +333,8 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
share->table_share= table_share;
DBUG_ASSERT(share->table == 0);
share->table= table;
+ /* We can't use 'use_all_columns()' as the file object is not setup yet */
+ table->column_bitmaps_set_no_signal(&table->s->all_set, &table->s->all_set);
#ifndef DBUG_OFF
dbug_print_table("table", table);
#endif
@@ -343,7 +368,7 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
{
bitmap_init(&share->subscriber_bitmap[i],
(Uint32*)alloc_root(mem_root, max_ndb_nodes/8),
- max_ndb_nodes, false);
+ max_ndb_nodes, FALSE);
bitmap_clear_all(&share->subscriber_bitmap[i]);
}
}
@@ -366,10 +391,9 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
while (1)
{
int error;
- TABLE_SHARE *table_share=
- (TABLE_SHARE *) my_malloc(sizeof(*table_share), MYF(MY_WME));
- TABLE *table= (TABLE*) my_malloc(sizeof(*table), MYF(MY_WME));
- if ((error= ndbcluster_binlog_open_table(thd, share, table_share, table)))
+ TABLE_SHARE *table_share= (TABLE_SHARE *) alloc_root(mem_root, sizeof(*table_share));
+ TABLE *table= (TABLE*) alloc_root(mem_root, sizeof(*table));
+ if ((error= ndbcluster_binlog_open_table(thd, share, table_share, table, 0)))
break;
/*
! do not touch the contents of the table
@@ -490,6 +514,7 @@ ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command,
{
case LOGCOM_CREATE_TABLE:
type= SOT_CREATE_TABLE;
+ DBUG_ASSERT(FALSE);
break;
case LOGCOM_ALTER_TABLE:
type= SOT_ALTER_TABLE;
@@ -497,9 +522,11 @@ ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command,
break;
case LOGCOM_RENAME_TABLE:
type= SOT_RENAME_TABLE;
+ DBUG_ASSERT(FALSE);
break;
case LOGCOM_DROP_TABLE:
type= SOT_DROP_TABLE;
+ DBUG_ASSERT(FALSE);
break;
case LOGCOM_CREATE_DB:
type= SOT_CREATE_DB;
@@ -511,12 +538,14 @@ ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command,
break;
case LOGCOM_DROP_DB:
type= SOT_DROP_DB;
+ DBUG_ASSERT(FALSE);
break;
}
if (log)
{
ndbcluster_log_schema_op(thd, 0, query, query_length,
- db, table_name, 0, 0, type);
+ db, table_name, 0, 0, type,
+ 0, 0, 0);
}
DBUG_VOID_RETURN;
}
@@ -867,6 +896,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
/* unpack blob values */
byte* blobs_buffer= 0;
uint blobs_buffer_size= 0;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
{
ptrdiff_t ptrdiff= 0;
int ret= get_ndb_blobs_value(table, share->ndb_value[0],
@@ -876,7 +906,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
{
my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
DBUG_PRINT("info", ("blob read error"));
- DBUG_ASSERT(false);
+ DBUG_ASSERT(FALSE);
}
}
/* db varchar 1 length byte */
@@ -928,6 +958,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
s->type= ((Field_long *)*field)->val_int();
/* free blobs buffer */
my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ dbug_tmp_restore_column_map(table->read_set, old_map);
}
/*
@@ -954,6 +985,154 @@ static char *ndb_pack_varchar(const NDBCOL *col, char *buf,
}
/*
+ acknowledge handling of schema operation
+*/
+static int
+ndbcluster_update_slock(THD *thd,
+ const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("ndbcluster_update_slock");
+ if (!schema_share)
+ {
+ DBUG_RETURN(0);
+ }
+
+ const NdbError *ndb_error= 0;
+ uint32 node_id= g_ndb_cluster_connection->node_id();
+ Ndb *ndb= check_ndb_in_thd(thd);
+ char save_db[FN_HEADLEN];
+ strcpy(save_db, ndb->getDatabaseName());
+
+ char tmp_buf[FN_REFLEN];
+ NDBDICT *dict= ndb->getDictionary();
+ ndb->setDatabaseName(NDB_REP_DB);
+ Ndb_table_guard ndbtab_g(dict, NDB_SCHEMA_TABLE);
+ const NDBTAB *ndbtab= ndbtab_g.get_table();
+ NdbTransaction *trans= 0;
+ int retries= 100;
+ const NDBCOL *col[SCHEMA_SIZE];
+ unsigned sz[SCHEMA_SIZE];
+
+ MY_BITMAP slock;
+ uint32 bitbuf[SCHEMA_SLOCK_SIZE/4];
+ bitmap_init(&slock, bitbuf, sizeof(bitbuf)*8, false);
+
+ if (ndbtab == 0)
+ {
+ abort();
+ DBUG_RETURN(0);
+ }
+
+ {
+ uint i;
+ for (i= 0; i < SCHEMA_SIZE; i++)
+ {
+ col[i]= ndbtab->getColumn(i);
+ if (i != SCHEMA_QUERY_I)
+ {
+ sz[i]= col[i]->getLength();
+ DBUG_ASSERT(sz[i] <= sizeof(tmp_buf));
+ }
+ }
+ }
+
+ while (1)
+ {
+ if ((trans= ndb->startTransaction()) == 0)
+ goto err;
+ {
+ NdbOperation *op= 0;
+ int r= 0;
+
+ /* read the bitmap exlusive */
+ r|= (op= trans->getNdbOperation(ndbtab)) == 0;
+ DBUG_ASSERT(r == 0);
+ r|= op->readTupleExclusive();
+ DBUG_ASSERT(r == 0);
+
+ /* db */
+ ndb_pack_varchar(col[SCHEMA_DB_I], tmp_buf, db, strlen(db));
+ r|= op->equal(SCHEMA_DB_I, tmp_buf);
+ DBUG_ASSERT(r == 0);
+ /* name */
+ ndb_pack_varchar(col[SCHEMA_NAME_I], tmp_buf, table_name,
+ strlen(table_name));
+ r|= op->equal(SCHEMA_NAME_I, tmp_buf);
+ DBUG_ASSERT(r == 0);
+ /* slock */
+ r|= op->getValue(SCHEMA_SLOCK_I, (char*)slock.bitmap) == 0;
+ DBUG_ASSERT(r == 0);
+ }
+ if (trans->execute(NdbTransaction::NoCommit))
+ goto err;
+ bitmap_clear_bit(&slock, node_id);
+ {
+ NdbOperation *op= 0;
+ int r= 0;
+
+ /* now update the tuple */
+ r|= (op= trans->getNdbOperation(ndbtab)) == 0;
+ DBUG_ASSERT(r == 0);
+ r|= op->updateTuple();
+ DBUG_ASSERT(r == 0);
+
+ /* db */
+ ndb_pack_varchar(col[SCHEMA_DB_I], tmp_buf, db, strlen(db));
+ r|= op->equal(SCHEMA_DB_I, tmp_buf);
+ DBUG_ASSERT(r == 0);
+ /* name */
+ ndb_pack_varchar(col[SCHEMA_NAME_I], tmp_buf, table_name,
+ strlen(table_name));
+ r|= op->equal(SCHEMA_NAME_I, tmp_buf);
+ DBUG_ASSERT(r == 0);
+ /* slock */
+ r|= op->setValue(SCHEMA_SLOCK_I, (char*)slock.bitmap);
+ DBUG_ASSERT(r == 0);
+ /* node_id */
+ r|= op->setValue(SCHEMA_NODE_ID_I, node_id);
+ DBUG_ASSERT(r == 0);
+ /* type */
+ r|= op->setValue(SCHEMA_TYPE_I, (uint32)SOT_CLEAR_SLOCK);
+ DBUG_ASSERT(r == 0);
+ }
+ if (trans->execute(NdbTransaction::Commit) == 0)
+ {
+ dict->forceGCPWait();
+ DBUG_PRINT("info", ("node %d cleared lock on '%s.%s'",
+ node_id, db, table_name));
+ break;
+ }
+ err:
+ const NdbError *this_error= trans ?
+ &trans->getNdbError() : &ndb->getNdbError();
+ if (this_error->status == NdbError::TemporaryError)
+ {
+ if (retries--)
+ {
+ if (trans)
+ ndb->closeTransaction(trans);
+ continue; // retry
+ }
+ }
+ ndb_error= this_error;
+ break;
+ }
+end:
+ if (ndb_error)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
+ ndb_error->code,
+ ndb_error->message,
+ "Could not release lock on '%s.%s'",
+ db, table_name);
+ if (trans)
+ ndb->closeTransaction(trans);
+ ndb->setDatabaseName(save_db);
+ DBUG_RETURN(0);
+}
+
+/*
log query in schema table
*/
static void ndb_report_waiting(const char *key,
@@ -987,7 +1166,8 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_id,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
- const char *new_db, const char *new_table_name)
+ const char *new_db, const char *new_table_name,
+ int have_lock_open)
{
DBUG_ENTER("ndbcluster_log_schema_op");
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@@ -1068,12 +1248,12 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
Uint64 epoch= 0;
MY_BITMAP schema_subscribers;
uint32 bitbuf[sizeof(ndb_schema_object->slock)/4];
- uint32 bitbuf_e[sizeof(bitbuf)];
- bzero((char *)bitbuf_e, sizeof(bitbuf_e));
+ char bitbuf_e[sizeof(bitbuf)];
+ bzero(bitbuf_e, sizeof(bitbuf_e));
{
int i, updated= 0;
int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes();
- bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, false);
+ bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE);
bitmap_set_all(&schema_subscribers);
(void) pthread_mutex_lock(&schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
@@ -1088,7 +1268,17 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
}
(void) pthread_mutex_unlock(&schema_share->mutex);
if (updated)
+ {
bitmap_clear_bit(&schema_subscribers, node_id);
+ /*
+ if setting own acknowledge bit it is important that
+ no other mysqld's are registred, as subsequent code
+ will cause the original event to be hidden (by blob
+ merge event code)
+ */
+ if (bitmap_is_clear_all(&schema_subscribers))
+ bitmap_set_bit(&schema_subscribers, node_id);
+ }
else
bitmap_clear_all(&schema_subscribers);
@@ -1201,7 +1391,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
{
log_db= new_db;
log_tab= new_table_name;
- log_subscribers= (const char *)bitbuf_e; // no ack expected on this
+ log_subscribers= bitbuf_e; // no ack expected on this
log_type= (uint32)SOT_RENAME_TABLE_NEW;
continue;
}
@@ -1209,7 +1399,6 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
}
if (trans->execute(NdbTransaction::Commit) == 0)
{
- dict->forceGCPWait();
DBUG_PRINT("info", ("logged: %s", query));
break;
}
@@ -1230,7 +1419,7 @@ err:
}
end:
if (ndb_error)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndb_error->code,
ndb_error->message,
@@ -1246,8 +1435,22 @@ end:
if (ndb_error == 0 &&
!bitmap_is_clear_all(&schema_subscribers))
{
- int max_timeout= 10;
+ /*
+ if own nodeid is set we are a single mysqld registred
+ as an optimization we update the slock directly
+ */
+ if (bitmap_is_set(&schema_subscribers, node_id))
+ ndbcluster_update_slock(thd, db, table_name);
+ else
+ dict->forceGCPWait();
+
+ int max_timeout= opt_ndb_sync_timeout;
(void) pthread_mutex_lock(&ndb_schema_object->mutex);
+ if (have_lock_open)
+ {
+ safe_mutex_assert_owner(&LOCK_open);
+ (void) pthread_mutex_unlock(&LOCK_open);
+ }
while (1)
{
struct timespec abstime;
@@ -1257,7 +1460,8 @@ end:
int ret= pthread_cond_timedwait(&injector_cond,
&ndb_schema_object->mutex,
&abstime);
-
+ if (thd->killed)
+ break;
(void) pthread_mutex_lock(&schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
@@ -1292,6 +1496,10 @@ end:
"distributing", ndb_schema_object->key);
}
}
+ if (have_lock_open)
+ {
+ (void) pthread_mutex_lock(&LOCK_open);
+ }
(void) pthread_mutex_unlock(&ndb_schema_object->mutex);
}
@@ -1302,154 +1510,6 @@ end:
}
/*
- acknowledge handling of schema operation
-*/
-static int
-ndbcluster_update_slock(THD *thd,
- const char *db,
- const char *table_name)
-{
- DBUG_ENTER("ndbcluster_update_slock");
- if (!schema_share)
- {
- DBUG_RETURN(0);
- }
-
- const NdbError *ndb_error= 0;
- uint32 node_id= g_ndb_cluster_connection->node_id();
- Ndb *ndb= check_ndb_in_thd(thd);
- char save_db[FN_HEADLEN];
- strcpy(save_db, ndb->getDatabaseName());
-
- char tmp_buf[FN_REFLEN];
- NDBDICT *dict= ndb->getDictionary();
- ndb->setDatabaseName(NDB_REP_DB);
- Ndb_table_guard ndbtab_g(dict, NDB_SCHEMA_TABLE);
- const NDBTAB *ndbtab= ndbtab_g.get_table();
- NdbTransaction *trans= 0;
- int retries= 100;
- const NDBCOL *col[SCHEMA_SIZE];
- unsigned sz[SCHEMA_SIZE];
-
- MY_BITMAP slock;
- uint32 bitbuf[SCHEMA_SLOCK_SIZE/4];
- bitmap_init(&slock, bitbuf, sizeof(bitbuf)*8, false);
-
- if (ndbtab == 0)
- {
- abort();
- DBUG_RETURN(0);
- }
-
- {
- uint i;
- for (i= 0; i < SCHEMA_SIZE; i++)
- {
- col[i]= ndbtab->getColumn(i);
- if (i != SCHEMA_QUERY_I)
- {
- sz[i]= col[i]->getLength();
- DBUG_ASSERT(sz[i] <= sizeof(tmp_buf));
- }
- }
- }
-
- while (1)
- {
- if ((trans= ndb->startTransaction()) == 0)
- goto err;
- {
- NdbOperation *op= 0;
- int r= 0;
-
- /* read the bitmap exlusive */
- r|= (op= trans->getNdbOperation(ndbtab)) == 0;
- DBUG_ASSERT(r == 0);
- r|= op->readTupleExclusive();
- DBUG_ASSERT(r == 0);
-
- /* db */
- ndb_pack_varchar(col[SCHEMA_DB_I], tmp_buf, db, strlen(db));
- r|= op->equal(SCHEMA_DB_I, tmp_buf);
- DBUG_ASSERT(r == 0);
- /* name */
- ndb_pack_varchar(col[SCHEMA_NAME_I], tmp_buf, table_name,
- strlen(table_name));
- r|= op->equal(SCHEMA_NAME_I, tmp_buf);
- DBUG_ASSERT(r == 0);
- /* slock */
- r|= op->getValue(SCHEMA_SLOCK_I, (char*)slock.bitmap) == 0;
- DBUG_ASSERT(r == 0);
- }
- if (trans->execute(NdbTransaction::NoCommit))
- goto err;
- bitmap_clear_bit(&slock, node_id);
- {
- NdbOperation *op= 0;
- int r= 0;
-
- /* now update the tuple */
- r|= (op= trans->getNdbOperation(ndbtab)) == 0;
- DBUG_ASSERT(r == 0);
- r|= op->updateTuple();
- DBUG_ASSERT(r == 0);
-
- /* db */
- ndb_pack_varchar(col[SCHEMA_DB_I], tmp_buf, db, strlen(db));
- r|= op->equal(SCHEMA_DB_I, tmp_buf);
- DBUG_ASSERT(r == 0);
- /* name */
- ndb_pack_varchar(col[SCHEMA_NAME_I], tmp_buf, table_name,
- strlen(table_name));
- r|= op->equal(SCHEMA_NAME_I, tmp_buf);
- DBUG_ASSERT(r == 0);
- /* slock */
- r|= op->setValue(SCHEMA_SLOCK_I, (char*)slock.bitmap);
- DBUG_ASSERT(r == 0);
- /* node_id */
- r|= op->setValue(SCHEMA_NODE_ID_I, node_id);
- DBUG_ASSERT(r == 0);
- /* type */
- r|= op->setValue(SCHEMA_TYPE_I, (uint32)SOT_CLEAR_SLOCK);
- DBUG_ASSERT(r == 0);
- }
- if (trans->execute(NdbTransaction::Commit) == 0)
- {
- dict->forceGCPWait();
- DBUG_PRINT("info", ("node %d cleared lock on '%s.%s'",
- node_id, db, table_name));
- break;
- }
- err:
- const NdbError *this_error= trans ?
- &trans->getNdbError() : &ndb->getNdbError();
- if (this_error->status == NdbError::TemporaryError)
- {
- if (retries--)
- {
- if (trans)
- ndb->closeTransaction(trans);
- continue; // retry
- }
- }
- ndb_error= this_error;
- break;
- }
-end:
- if (ndb_error)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
- ndb_error->code,
- ndb_error->message,
- "Could not release lock on '%s.%s'",
- db, table_name);
- if (trans)
- ndb->closeTransaction(trans);
- ndb->setDatabaseName(save_db);
- DBUG_RETURN(0);
-}
-
-/*
Handle _non_ data events from the storage nodes
*/
int
@@ -1535,6 +1595,10 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
sql_print_information("NDB: Failed write frm for %s.%s, error %d",
dbname, tabname, error);
}
+
+ // copy names as memory will be freed
+ NdbAutoPtr<char> a1((char *)(dbname= strdup(dbname)));
+ NdbAutoPtr<char> a2((char *)(tabname= strdup(tabname)));
ndbcluster_binlog_close_table(thd, share);
TABLE_LIST table_list;
@@ -1543,10 +1607,16 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
table_list.alias= table_list.table_name= (char *)tabname;
close_cached_tables(thd, 0, &table_list, TRUE);
- if ((error= ndbcluster_binlog_open_table(thd, share,
- table_share, table)))
+ if ((error= ndbcluster_binlog_open_table(thd, share,
+ table_share, table, 1)))
sql_print_information("NDB: Failed to re-open table %s.%s",
dbname, tabname);
+
+ table= share->table;
+ table_share= share->table_share;
+ dbname= table_share->db.str;
+ tabname= table_share->table_name.str;
+
pthread_mutex_unlock(&LOCK_open);
}
my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
@@ -1659,20 +1729,29 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
Cluster_schema *schema= (Cluster_schema *)
sql_alloc(sizeof(Cluster_schema));
MY_BITMAP slock;
- bitmap_init(&slock, schema->slock, 8*SCHEMA_SLOCK_SIZE, false);
+ bitmap_init(&slock, schema->slock, 8*SCHEMA_SLOCK_SIZE, FALSE);
uint node_id= g_ndb_cluster_connection->node_id();
ndbcluster_get_schema(tmp_share, schema);
+ enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
+ DBUG_PRINT("info",
+ ("%s.%s: log query_length: %d query: '%s' type: %d",
+ schema->db, schema->name,
+ schema->query_length, schema->query,
+ schema_type));
+ if (schema_type == SOT_CLEAR_SLOCK)
+ {
+ /*
+ handle slock after epoch is completed to ensure that
+ schema events get inserted in the binlog after any data
+ events
+ */
+ post_epoch_log_list->push_back(schema, mem_root);
+ DBUG_RETURN(0);
+ }
if (schema->node_id != node_id)
{
int log_query= 0, post_epoch_unlock= 0;
- DBUG_PRINT("info",
- ("%s.%s: log query_length: %d query: '%s' type: %d",
- schema->db, schema->name,
- schema->query_length, schema->query,
- schema->type));
- char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), schema->db, schema->name, "");
- switch ((enum SCHEMA_OP_TYPE)schema->type)
+ switch (schema_type)
{
case SOT_DROP_TABLE:
// fall through
@@ -1720,30 +1799,12 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
TRUE, /* print error */
FALSE); /* binlog the query */
break;
- case SOT_CLEAR_SLOCK:
- {
- pthread_mutex_lock(&ndbcluster_mutex);
- NDB_SCHEMA_OBJECT *ndb_schema_object=
- (NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
- (byte*) key, strlen(key));
- if (ndb_schema_object)
- {
- pthread_mutex_lock(&ndb_schema_object->mutex);
- memcpy(ndb_schema_object->slock, schema->slock,
- sizeof(ndb_schema_object->slock));
- DBUG_DUMP("ndb_schema_object->slock_bitmap.bitmap",
- (char*)ndb_schema_object->slock_bitmap.bitmap,
- no_bytes_in_map(&ndb_schema_object->slock_bitmap));
- pthread_mutex_unlock(&ndb_schema_object->mutex);
- pthread_cond_signal(&injector_cond);
- }
- pthread_mutex_unlock(&ndbcluster_mutex);
- DBUG_RETURN(0);
- }
case SOT_TABLESPACE:
case SOT_LOGFILE_GROUP:
log_query= 1;
break;
+ case SOT_CLEAR_SLOCK:
+ abort();
}
if (log_query && ndb_binlog_running)
{
@@ -1776,7 +1837,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
break;
case NDBEVENT::TE_CLUSTER_FAILURE:
if (ndb_extra_logging)
- sql_print_information("NDB Binlog: cluster failure for %s.", schema_share->key);
+ sql_print_information("NDB Binlog: cluster failure for %s at epoch %u.",
+ schema_share->key, (unsigned) pOp->getGCI());
// fall through
case NDBEVENT::TE_DROP:
if (ndb_extra_logging &&
@@ -1785,7 +1847,6 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
"read only on reconnect.");
free_share(&schema_share);
schema_share= 0;
- ndb_binlog_tables_inited= FALSE;
close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, FALSE);
// fall through
case NDBEVENT::TE_ALTER:
@@ -1884,10 +1945,30 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
schema->type));
int log_query= 0;
{
+ enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
char key[FN_REFLEN];
build_table_filename(key, sizeof(key), schema->db, schema->name, "");
- NDB_SHARE *share= get_share(key, 0, false, false);
- enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
+ if (schema_type == SOT_CLEAR_SLOCK)
+ {
+ pthread_mutex_lock(&ndbcluster_mutex);
+ NDB_SCHEMA_OBJECT *ndb_schema_object=
+ (NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
+ (byte*) key, strlen(key));
+ if (ndb_schema_object)
+ {
+ pthread_mutex_lock(&ndb_schema_object->mutex);
+ memcpy(ndb_schema_object->slock, schema->slock,
+ sizeof(ndb_schema_object->slock));
+ DBUG_DUMP("ndb_schema_object->slock_bitmap.bitmap",
+ (char*)ndb_schema_object->slock_bitmap.bitmap,
+ no_bytes_in_map(&ndb_schema_object->slock_bitmap));
+ pthread_mutex_unlock(&ndb_schema_object->mutex);
+ pthread_cond_signal(&injector_cond);
+ }
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ continue;
+ }
+ NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
switch (schema_type)
{
case SOT_DROP_DB:
@@ -1951,7 +2032,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
}
break;
default:
- DBUG_ASSERT(false);
+ DBUG_ASSERT(FALSE);
}
if (share)
{
@@ -2028,18 +2109,20 @@ static int open_binlog_index(THD *thd, TABLE_LIST *tables,
}
*binlog_index= tables->table;
thd->proc_info= save_proc_info;
+ (*binlog_index)->use_all_columns();
return 0;
}
+
/*
Insert one row in the binlog_index
*/
+
int ndb_add_binlog_index(THD *thd, void *_row)
{
Binlog_index_row &row= *(Binlog_index_row *) _row;
int error= 0;
bool need_reopen;
-
/*
Turn of binlogging to prevent the table changes to be written to
the binary log.
@@ -2081,10 +2164,9 @@ int ndb_add_binlog_index(THD *thd, void *_row)
binlog_index->field[5]->store(row.n_deletes);
binlog_index->field[6]->store(row.n_schemaops);
- int r;
- if ((r= binlog_index->file->ha_write_row(binlog_index->record[0])))
+ if ((error= binlog_index->file->ha_write_row(binlog_index->record[0])))
{
- sql_print_error("NDB Binlog: Writing row to binlog_index: %d", r);
+ sql_print_error("NDB Binlog: Writing row to binlog_index: %d", error);
error= -1;
goto add_binlog_index_err;
}
@@ -2218,7 +2300,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
}
/* Create share which is needed to hold replication information */
- if (!(share= get_share(key, 0, true, true)))
+ if (!(share= get_share(key, 0, TRUE, TRUE)))
{
sql_print_error("NDB Binlog: "
"allocating table share for %s failed", key);
@@ -2310,6 +2392,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
const char *event_name, NDB_SHARE *share,
int push_warning)
{
+ THD *thd= current_thd;
DBUG_ENTER("ndbcluster_create_event");
DBUG_PRINT("info", ("table=%s version=%d event=%s share=%s",
ndbtab->getName(), ndbtab->getObjectVersion(),
@@ -2339,12 +2422,12 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
"with BLOB attribute and no PK is not supported",
share->key);
if (push_warning)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
- ndbcluster_hton.name,
+ ndbcluster_hton_name,
"Binlog of table with BLOB attribute and no PK");
-
+
share->flags|= NSF_NO_BINLOG;
DBUG_RETURN(-1);
}
@@ -2368,7 +2451,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
}
}
if (share->flags & NSF_BLOB_FLAG)
- my_event.mergeEvents(true);
+ my_event.mergeEvents(TRUE);
/* add all columns to the event */
int n_cols= ndbtab->getNoOfColumns();
@@ -2383,7 +2466,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
failed, print a warning
*/
if (push_warning)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2411,7 +2494,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
dict->dropEvent(my_event.getName()))
{
if (push_warning)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2430,7 +2513,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
if (dict->createEvent(my_event))
{
if (push_warning)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2443,7 +2526,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
DBUG_RETURN(-1);
}
#ifdef NDB_BINLOG_EXTRA_WARNINGS
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
0, "NDB Binlog: Removed trailing event",
"NDB");
@@ -2472,6 +2555,7 @@ int
ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
const char *event_name)
{
+ THD *thd= current_thd;
/*
we are in either create table or rename table so table should be
locked, hence we can work with the share without locks
@@ -2545,7 +2629,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
{
sql_print_error("NDB Binlog: Creating NdbEventOperation failed for"
" %s",event_name);
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndb->getNdbError().code,
ndb->getNdbError().message,
@@ -2555,7 +2639,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
}
if (share->flags & NSF_BLOB_FLAG)
- op->mergeEvents(true); // currently not inherited from event
+ op->mergeEvents(TRUE); // currently not inherited from event
DBUG_PRINT("info", ("share->ndb_value[0]: 0x%x",
share->ndb_value[0]));
@@ -2595,7 +2679,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
sql_print_error("NDB Binlog: Creating NdbEventOperation"
" blob field %u handles failed (code=%d) for %s",
j, op->getNdbError().code, event_name);
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
op->getNdbError().code,
op->getNdbError().message,
@@ -2632,7 +2716,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
retries= 0;
if (retries == 0)
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
op->getNdbError().code, op->getNdbError().message,
"NDB");
@@ -2680,6 +2764,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
NDB_SHARE *share, const char *type_str)
{
DBUG_ENTER("ndbcluster_handle_drop_table");
+ THD *thd= current_thd;
NDBDICT *dict= ndb->getDictionary();
if (event_name && dict->dropEvent(event_name))
@@ -2687,7 +2772,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
if (dict->getNdbError().code != 4710)
{
/* drop event failed for some reason, issue a warning */
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2702,7 +2787,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
share->op->getState() == NdbEventOperation::EO_EXECUTING &&
dict->getNdbError().code != 4009)
{
- DBUG_ASSERT(false);
+ DBUG_ASSERT(FALSE);
DBUG_RETURN(-1);
}
}
@@ -2725,10 +2810,14 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
these out of order, thus we are keeping the SYNC_DROP_ defined
for now.
*/
+ const char *save_proc_info= thd->proc_info;
#define SYNC_DROP_
#ifdef SYNC_DROP_
+ thd->proc_info= "Syncing ndb table schema operation and binlog";
(void) pthread_mutex_lock(&share->mutex);
- int max_timeout= 10;
+ safe_mutex_assert_owner(&LOCK_open);
+ (void) pthread_mutex_unlock(&LOCK_open);
+ int max_timeout= opt_ndb_sync_timeout;
while (share->op)
{
struct timespec abstime;
@@ -2736,7 +2825,8 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
int ret= pthread_cond_timedwait(&injector_cond,
&share->mutex,
&abstime);
- if (share->op == 0)
+ if (thd->killed ||
+ share->op == 0)
break;
if (ret)
{
@@ -2752,6 +2842,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
type_str, share->key);
}
}
+ (void) pthread_mutex_lock(&LOCK_open);
(void) pthread_mutex_unlock(&share->mutex);
#else
(void) pthread_mutex_lock(&share->mutex);
@@ -2759,6 +2850,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
share->op= 0;
(void) pthread_mutex_unlock(&share->mutex);
#endif
+ thd->proc_info= save_proc_info;
DBUG_RETURN(0);
}
@@ -2823,13 +2915,14 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
/* make sure to flush any pending events as they can be dependent
on one of the tables being changed below
*/
- thd->binlog_flush_pending_rows_event(true);
+ thd->binlog_flush_pending_rows_event(TRUE);
switch (type)
{
case NDBEVENT::TE_CLUSTER_FAILURE:
if (ndb_extra_logging)
- sql_print_information("NDB Binlog: cluster failure for %s.", share->key);
+ sql_print_information("NDB Binlog: cluster failure for %s at epoch %u.",
+ share->key, (unsigned) pOp->getGCI());
if (apply_status_share == share)
{
if (ndb_extra_logging &&
@@ -2838,7 +2931,6 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
"read only on reconnect.");
free_share(&apply_status_share);
apply_status_share= 0;
- ndb_binlog_tables_inited= FALSE;
}
DBUG_PRINT("info", ("CLUSTER FAILURE EVENT: "
"%s received share: 0x%lx op: %lx share op: %lx "
@@ -2854,7 +2946,6 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
"read only on reconnect.");
free_share(&apply_status_share);
apply_status_share= 0;
- ndb_binlog_tables_inited= FALSE;
}
/* ToDo: remove printout */
if (ndb_extra_logging)
@@ -2908,7 +2999,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/* Potential buffer for the bitmap */
uint32 bitbuf[128 / (sizeof(uint32) * 8)];
bitmap_init(&b, n_fields <= sizeof(bitbuf) * 8 ? bitbuf : NULL,
- n_fields, false);
+ n_fields, FALSE);
bitmap_set_all(&b);
/*
@@ -2941,7 +3032,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
}
ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
int ret= trans.write_row(::server_id,
- injector::transaction::table(table, true),
+ injector::transaction::table(table, TRUE),
&b, n_fields, table->record[0]);
DBUG_ASSERT(ret == 0);
}
@@ -2979,7 +3070,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
DBUG_EXECUTE("info", print_records(table, table->record[n]););
int ret= trans.delete_row(::server_id,
- injector::transaction::table(table, true),
+ injector::transaction::table(table, TRUE),
&b, n_fields, table->record[n]);
DBUG_ASSERT(ret == 0);
}
@@ -3006,7 +3097,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
since table has a primary key, we can do a write
using only after values
*/
- trans.write_row(::server_id, injector::transaction::table(table, true),
+ trans.write_row(::server_id, injector::transaction::table(table, TRUE),
&b, n_fields, table->record[0]);// after values
}
else
@@ -3026,7 +3117,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
DBUG_EXECUTE("info", print_records(table, table->record[1]););
int ret= trans.update_row(::server_id,
- injector::transaction::table(table, true),
+ injector::transaction::table(table, TRUE),
&b, n_fields,
table->record[1], // before values
table->record[0]);// after values
@@ -3118,7 +3209,7 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
}
pthread_mutex_init(&ndb_schema_object->mutex, MY_MUTEX_INIT_FAST);
bitmap_init(&ndb_schema_object->slock_bitmap, ndb_schema_object->slock,
- sizeof(ndb_schema_object->slock)*8, false);
+ sizeof(ndb_schema_object->slock)*8, FALSE);
bitmap_clear_all(&ndb_schema_object->slock_bitmap);
break;
}
@@ -3267,46 +3358,43 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
pthread_mutex_unlock(&injector_mutex);
pthread_cond_signal(&injector_cond);
- thd->proc_info= "Waiting for ndbcluster to start";
-
- pthread_mutex_lock(&injector_mutex);
- while (!schema_share ||
- (ndb_binlog_running && !apply_status_share))
- {
- /* ndb not connected yet */
- struct timespec abstime;
- set_timespec(abstime, 1);
- pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
- if (abort_loop)
- {
- pthread_mutex_unlock(&injector_mutex);
- goto err;
- }
- }
- pthread_mutex_unlock(&injector_mutex);
-
+restart:
/*
Main NDB Injector loop
*/
-
- DBUG_ASSERT(ndbcluster_hton.slot != ~(uint)0);
- if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
- {
- sql_print_error("Could not allocate Thd_ndb object");
- goto err;
- }
- set_thd_ndb(thd, thd_ndb);
- thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
- thd->query_id= 0; // to keep valgrind quiet
{
- static char db[]= "";
- thd->db= db;
- if (ndb_binlog_running)
- open_binlog_index(thd, &binlog_tables, &binlog_index);
- thd->db= db;
+ thd->proc_info= "Waiting for ndbcluster to start";
+
+ pthread_mutex_lock(&injector_mutex);
+ while (!schema_share ||
+ (ndb_binlog_running && !apply_status_share))
+ {
+ /* ndb not connected yet */
+ struct timespec abstime;
+ set_timespec(abstime, 1);
+ pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
+ if (abort_loop)
+ {
+ pthread_mutex_unlock(&injector_mutex);
+ goto err;
+ }
+ }
+ pthread_mutex_unlock(&injector_mutex);
+
+ if (thd_ndb == NULL)
+ {
+ DBUG_ASSERT(ndbcluster_hton.slot != ~(uint)0);
+ if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
+ {
+ sql_print_error("Could not allocate Thd_ndb object");
+ goto err;
+ }
+ set_thd_ndb(thd, thd_ndb);
+ thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
+ thd->query_id= 0; // to keep valgrind quiet
+ }
}
-restart:
{
// wait for the first event
thd->proc_info= "Waiting for first event from ndbcluster";
@@ -3321,6 +3409,9 @@ restart:
DBUG_PRINT("info", ("schema_res: %d schema_gci: %d", schema_res, schema_gci));
if (schema_res > 0)
{
+ i_ndb->pollEvents(0);
+ i_ndb->flushIncompleteEvents(schema_gci);
+ s_ndb->flushIncompleteEvents(schema_gci);
if (schema_gci < ndb_latest_handled_binlog_epoch)
{
sql_print_error("NDB Binlog: cluster has been restarted --initial or with older filesystem. "
@@ -3334,7 +3425,13 @@ restart:
}
}
}
-
+ {
+ static char db[]= "";
+ thd->db= db;
+ if (ndb_binlog_running)
+ open_binlog_index(thd, &binlog_tables, &binlog_index);
+ thd->db= db;
+ }
do_ndbcluster_binlog_close_connection= BCCC_running;
for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) &&
ndb_latest_handled_binlog_epoch >= g_latest_trans_gci) &&
@@ -3523,7 +3620,7 @@ restart:
inj->new_trans(thd, &trans);
}
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
- injector::transaction::table tbl(table, true);
+ injector::transaction::table tbl(table, TRUE);
int ret= trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
}
@@ -3536,20 +3633,14 @@ restart:
const LEX_STRING& name=table->s->table_name;
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
- injector::transaction::table tbl(table, true);
+ injector::transaction::table tbl(table, TRUE);
int ret= trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
-
- MY_BITMAP b;
- uint32 bitbuf;
- DBUG_ASSERT(table->s->fields <= sizeof(bitbuf) * 8);
- bitmap_init(&b, &bitbuf, table->s->fields, false);
- bitmap_set_all(&b);
table->field[0]->store((longlong)::server_id);
table->field[1]->store((longlong)gci);
trans.write_row(::server_id,
- injector::transaction::table(table, true),
- &b, table->s->fields,
+ injector::transaction::table(table, TRUE),
+ &table->s->all_set, table->s->fields,
table->record[0]);
}
else
@@ -3683,7 +3774,12 @@ restart:
ndb_latest_handled_binlog_epoch= ndb_latest_received_binlog_epoch;
}
if (do_ndbcluster_binlog_close_connection == BCCC_restart)
+ {
+ ndb_binlog_tables_inited= FALSE;
+ close_thread_tables(thd);
+ binlog_index= 0;
goto restart;
+ }
err:
DBUG_PRINT("info",("Shutting down cluster binlog thread"));
thd->proc_info= "Shutting down";
@@ -3794,7 +3890,7 @@ ndbcluster_show_status_binlog(THD* thd, stat_print_fn *stat_print,
ndb_latest_received_binlog_epoch,
ndb_latest_handled_binlog_epoch,
ndb_latest_applied_binlog_epoch);
- if (stat_print(thd, ndbcluster_hton.name, strlen(ndbcluster_hton.name),
+ if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
"binlog", strlen("binlog"),
buf, buflen))
DBUG_RETURN(TRUE);
diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index d82cdccb1b9..7c45dee59d0 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -138,8 +138,9 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_id,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
- const char *new_db= 0,
- const char *new_table_name= 0);
+ const char *new_db,
+ const char *new_table_name,
+ int have_lock_open);
int ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
NDB_SHARE *share,
const char *type_str);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7b9dd00ed56..77a150994ad 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -69,50 +69,23 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE * table);
MODULE create/delete handler object
****************************************************************************/
-static handler *partition_create_handler(TABLE_SHARE *share);
+static handler *partition_create_handler(TABLE_SHARE *share,
+ MEM_ROOT *mem_root);
static uint partition_flags();
static uint alter_table_flags(uint flags);
-static const char partition_hton_name[]= "partition";
-static const char partition_hton_comment[]= "Partition Storage Engine Helper";
-
-handlerton partition_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- partition_hton_name,
- SHOW_OPTION_YES,
- partition_hton_comment, /* A comment used by SHOW to describe an engine */
- DB_TYPE_PARTITION_DB,
- 0, /* Method that initializes a storage engine */
- 0, /* slot */
- 0, /* savepoint size */
- NULL /*ndbcluster_close_connection*/,
- NULL, /* savepoint_set */
- NULL, /* savepoint_rollback */
- NULL, /* savepoint_release */
- NULL /*ndbcluster_commit*/,
- NULL /*ndbcluster_rollback*/,
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL,
- NULL,
- NULL,
- partition_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- NULL, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- partition_flags, /* Partition flags */
- alter_table_flags, /* Partition flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill FILES table */
- HTON_NOT_USER_SELECTABLE | HTON_HIDDEN,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
+handlerton partition_hton;
+
+static int partition_initialize()
+{
+ partition_hton.state= SHOW_OPTION_YES;
+ partition_hton.db_type= DB_TYPE_PARTITION_DB;
+ partition_hton.create= partition_create_handler;
+ partition_hton.partition_flags= partition_flags;
+ partition_hton.alter_table_flags= alter_table_flags;
+ partition_hton.flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
+ return 0;
+}
/*
Create new partition handler
@@ -125,9 +98,16 @@ handlerton partition_hton = {
New partition object
*/
-static handler *partition_create_handler(TABLE_SHARE *share)
+static handler *partition_create_handler(TABLE_SHARE *share,
+ MEM_ROOT *mem_root)
{
- return new ha_partition(share);
+ ha_partition *file= new (mem_root) ha_partition(share);
+ if (file && file->initialise_partition(mem_root))
+ {
+ delete file;
+ file= 0;
+ }
+ return file;
}
/*
@@ -229,7 +209,6 @@ void ha_partition::init_handler_variables()
m_reorged_parts= 0;
m_added_file= NULL;
m_tot_parts= 0;
- m_has_transactions= 0;
m_pkey_is_clustered= 0;
m_lock_type= F_UNLCK;
m_part_spec.start_part= NO_CURRENT_PART_ID;
@@ -301,7 +280,8 @@ ha_partition::~ha_partition()
Initialise partition handler object
SYNOPSIS
- ha_initialise()
+ initialise_partition()
+ mem_root Allocate memory through this
RETURN VALUE
1 Error
@@ -341,16 +321,16 @@ ha_partition::~ha_partition()
*/
-int ha_partition::ha_initialise()
+bool ha_partition::initialise_partition(MEM_ROOT *mem_root)
{
handler **file_array, *file;
- DBUG_ENTER("ha_partition::ha_initialise");
+ DBUG_ENTER("ha_partition::initialise_partition");
if (m_create_handler)
{
m_tot_parts= m_part_info->get_tot_partitions();
DBUG_ASSERT(m_tot_parts > 0);
- if (new_handlers_from_part_info())
+ if (new_handlers_from_part_info(mem_root))
DBUG_RETURN(1);
}
else if (!table_share || !table_share->normalized_path.str)
@@ -363,7 +343,7 @@ int ha_partition::ha_initialise()
m_table_flags|= HA_FILE_BASED | HA_REC_NOT_IN_SEQ;
DBUG_RETURN(0);
}
- else if (get_from_handler_file(table_share->normalized_path.str))
+ else if (get_from_handler_file(table_share->normalized_path.str, mem_root))
{
mem_alloc_error(2);
DBUG_RETURN(1);
@@ -377,12 +357,11 @@ int ha_partition::ha_initialise()
other parameters are calculated on demand.
HA_FILE_BASED is always set for partition handler since we use a
special file for handling names of partitions, engine types.
- HA_CAN_GEOMETRY, HA_CAN_FULLTEXT, HA_CAN_SQL_HANDLER, HA_DUPP_POS,
+ HA_CAN_GEOMETRY, HA_CAN_FULLTEXT, HA_CAN_SQL_HANDLER, HA_DUPLICATE_POS,
HA_CAN_INSERT_DELAYED is disabled until further investigated.
*/
m_table_flags= m_file[0]->table_flags();
m_low_byte_first= m_file[0]->low_byte_first();
- m_has_transactions= TRUE;
m_pkey_is_clustered= TRUE;
file_array= m_file;
do
@@ -394,13 +373,11 @@ int ha_partition::ha_initialise()
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
DBUG_RETURN(1);
}
- if (!file->has_transactions())
- m_has_transactions= FALSE;
if (!file->primary_key_is_clustered())
m_pkey_is_clustered= FALSE;
m_table_flags&= file->table_flags();
} while (*(++file_array));
- m_table_flags&= ~(HA_CAN_GEOMETRY | HA_CAN_FULLTEXT | HA_DUPP_POS |
+ m_table_flags&= ~(HA_CAN_GEOMETRY | HA_CAN_FULLTEXT | HA_DUPLICATE_POS |
HA_CAN_SQL_HANDLER | HA_CAN_INSERT_DELAYED);
m_table_flags|= HA_FILE_BASED | HA_REC_NOT_IN_SEQ;
DBUG_RETURN(0);
@@ -1108,8 +1085,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
part));
if ((error= handle_opt_part(thd, check_opt, m_file[part], flag)))
{
- my_error(ER_GET_ERRNO, MYF(0), error);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error);
}
} while (++j < no_subparts);
}
@@ -1118,8 +1094,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
DBUG_PRINT("info", ("Optimize partition %u", i));
if ((error= handle_opt_part(thd, check_opt, m_file[i], flag)))
{
- my_error(ER_GET_ERRNO, MYF(0), error);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error);
}
}
}
@@ -1388,9 +1363,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
uint j= 0;
do
{
- if (!(new_file_array[part_count++]= get_new_handler(table->s,
- thd->mem_root,
- part_elem->engine_type)))
+ if (!(new_file_array[part_count++]=
+ get_new_handler(table->s,
+ thd->mem_root,
+ part_elem->engine_type)))
{
mem_alloc_error(sizeof(handler));
DBUG_RETURN(ER_OUTOFMEMORY);
@@ -1644,7 +1620,7 @@ uint ha_partition::del_ren_cre_table(const char *from,
handler **file;
DBUG_ENTER("del_ren_cre_table()");
- if (get_from_handler_file(from))
+ if (get_from_handler_file(from, current_thd->mem_root))
DBUG_RETURN(TRUE);
DBUG_ASSERT(m_file_buffer);
name_buffer_ptr= m_name_buffer_ptr;
@@ -1953,7 +1929,6 @@ void ha_partition::clear_handler_file()
my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR));
m_file_buffer= NULL;
- m_name_buffer_ptr= NULL;
m_engine_array= NULL;
}
@@ -1962,29 +1937,29 @@ void ha_partition::clear_handler_file()
SYNOPSIS
create_handlers()
+ mem_root Allocate memory through this
RETURN VALUE
TRUE Error
FALSE Success
*/
-bool ha_partition::create_handlers()
+bool ha_partition::create_handlers(MEM_ROOT *mem_root)
{
uint i;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
DBUG_ENTER("create_handlers");
- if (!(m_file= (handler **) sql_alloc(alloc_len)))
+ if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
DBUG_RETURN(TRUE);
- bzero(m_file, alloc_len);
+ bzero((char*) m_file, alloc_len);
for (i= 0; i < m_tot_parts; i++)
{
- if (!(m_file[i]= get_new_handler(table_share, current_thd->mem_root,
+ if (!(m_file[i]= get_new_handler(table_share, mem_root,
m_engine_array[i])))
DBUG_RETURN(TRUE);
DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i]));
}
- m_file[m_tot_parts]= 0;
/* For the moment we only support partition over the same table engine */
if (m_engine_array[0] == &myisam_hton)
{
@@ -2005,13 +1980,14 @@ bool ha_partition::create_handlers()
SYNOPSIS
new_handlers_from_part_info()
+ mem_root Allocate memory through this
RETURN VALUE
TRUE Error
FALSE Success
*/
-bool ha_partition::new_handlers_from_part_info()
+bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
{
uint i, j, part_count;
partition_element *part_elem;
@@ -2020,12 +1996,12 @@ bool ha_partition::new_handlers_from_part_info()
THD *thd= current_thd;
DBUG_ENTER("ha_partition::new_handlers_from_part_info");
- if (!(m_file= (handler **) sql_alloc(alloc_len)))
+ if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
{
mem_alloc_error(alloc_len);
goto error_end;
}
- bzero(m_file, alloc_len);
+ bzero((char*) m_file, alloc_len);
DBUG_ASSERT(m_part_info->no_parts > 0);
i= 0;
@@ -2041,8 +2017,8 @@ bool ha_partition::new_handlers_from_part_info()
{
for (j= 0; j < m_part_info->no_subparts; j++)
{
- if (!(m_file[i]= get_new_handler(table_share, thd->mem_root,
- part_elem->engine_type)))
+ if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
+ part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u",
(uint) ha_legacy_type(part_elem->engine_type)));
@@ -2050,7 +2026,7 @@ bool ha_partition::new_handlers_from_part_info()
}
else
{
- if (!(m_file[part_count++]= get_new_handler(table_share, thd->mem_root,
+ if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u",
@@ -2076,6 +2052,7 @@ error_end:
SYNOPSIS
get_from_handler_file()
name Full path of table name
+ mem_root Allocate memory through this
RETURN VALUE
TRUE Error
@@ -2086,7 +2063,7 @@ error_end:
partitions.
*/
-bool ha_partition::get_from_handler_file(const char *name)
+bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
{
char buff[FN_REFLEN], *address_tot_name_len;
File file;
@@ -2125,7 +2102,8 @@ bool ha_partition::get_from_handler_file(const char *name)
goto err2;
for (i= 0; i < m_tot_parts; i++)
engine_array[i]= ha_resolve_by_legacy_type(current_thd,
- (enum legacy_db_type) *(uchar *) ((file_buffer) + 12 + i));
+ (enum legacy_db_type)
+ *(uchar *) ((file_buffer) + 12 + i));
address_tot_name_len= file_buffer + 12 + 4 * tot_partition_words;
tot_name_words= (uint4korr(address_tot_name_len) + 3) / 4;
if (len_words != (tot_partition_words + tot_name_words + 4))
@@ -2135,7 +2113,7 @@ bool ha_partition::get_from_handler_file(const char *name)
m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
m_name_buffer_ptr= name_buffer_ptr;
m_engine_array= engine_array;
- if (!m_file && create_handlers())
+ if (!m_file && create_handlers(mem_root))
{
clear_handler_file();
DBUG_RETURN(TRUE);
@@ -2189,7 +2167,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_mode= mode;
m_open_test_lock= test_if_locked;
m_part_field_array= m_part_info->full_part_field_array;
- if (get_from_handler_file(name))
+ if (get_from_handler_file(name, &table->mem_root))
DBUG_RETURN(1);
m_start_key.length= 0;
m_rec0= table->record[0];
@@ -2226,6 +2204,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
DBUG_RETURN(1);
bitmap_set_all(&(m_part_info->used_partitions));
+ /* Recalculate table flags as they may change after open */
+ m_table_flags= m_file[0]->table_flags();
file= m_file;
do
{
@@ -2237,7 +2217,11 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_no_locks+= (*file)->lock_count();
name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
set_if_bigger(ref_length, ((*file)->ref_length));
+ m_table_flags&= (*file)->table_flags();
} while (*(++file));
+ m_table_flags&= ~(HA_CAN_GEOMETRY | HA_CAN_FULLTEXT | HA_DUPLICATE_POS |
+ HA_CAN_SQL_HANDLER | HA_CAN_INSERT_DELAYED);
+ m_table_flags|= HA_FILE_BASED | HA_REC_NOT_IN_SEQ;
/*
Add 2 bytes for partition id in position ref length.
@@ -2600,6 +2584,7 @@ int ha_partition::write_row(byte * buf)
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
#ifdef NOT_NEEDED
if (likely(buf == rec0))
#endif
@@ -2614,6 +2599,7 @@ int ha_partition::write_row(byte * buf)
set_field_ptr(m_part_field_array, rec0, buf);
}
#endif
+ dbug_tmp_restore_column_map(table->read_set, old_map);
if (unlikely(error))
DBUG_RETURN(error);
m_last_part= part_id;
@@ -2805,7 +2791,7 @@ void ha_partition::start_bulk_insert(ha_rows rows)
file= m_file;
do
{
- (*file)->start_bulk_insert(rows);
+ (*file)->ha_start_bulk_insert(rows);
} while (*(++file));
DBUG_VOID_RETURN;
}
@@ -2832,7 +2818,7 @@ int ha_partition::end_bulk_insert()
do
{
int tmp;
- if ((tmp= (*file)->end_bulk_insert()))
+ if ((tmp= (*file)->ha_end_bulk_insert()))
error= tmp;
} while (*(++file));
DBUG_RETURN(error);
@@ -4070,7 +4056,7 @@ void ha_partition::include_partition_fields_in_used_fields()
do
{
- ha_set_bit_in_read_set((*ptr)->fieldnr);
+ bitmap_set_bit(table->read_set, (*ptr)->field_index);
} while (*(++ptr));
DBUG_VOID_RETURN;
}
@@ -4157,8 +4143,12 @@ void ha_partition::info(uint flag)
if (flag & HA_STATUS_AUTO)
{
+ ulonglong nb_reserved_values;
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
- auto_increment_value= get_auto_increment();
+ /* we don't want to reserve any values, it's pure information */
+ get_auto_increment(0, 0, 0, &stats.auto_increment_value,
+ &nb_reserved_values);
+ release_auto_increment();
}
if (flag & HA_STATUS_VARIABLE)
{
@@ -4182,12 +4172,12 @@ void ha_partition::info(uint flag)
check_time: Time of last check (only applicable to MyISAM)
We report last time of all underlying handlers
*/
- records= 0;
- deleted= 0;
- data_file_length= 0;
- index_file_length= 0;
- delete_length= 0;
- check_time= 0;
+ stats.records= 0;
+ stats.deleted= 0;
+ stats.data_file_length= 0;
+ stats.index_file_length= 0;
+ stats.check_time= 0;
+ stats.delete_length= 0;
file_array= m_file;
do
{
@@ -4195,22 +4185,22 @@ void ha_partition::info(uint flag)
{
file= *file_array;
file->info(HA_STATUS_VARIABLE);
- records+= file->records;
- deleted+= file->deleted;
- data_file_length+= file->data_file_length;
- index_file_length+= file->index_file_length;
- delete_length+= file->delete_length;
- if (file->check_time > check_time)
- check_time= file->check_time;
+ stats.records+= file->stats.records;
+ stats.deleted+= file->stats.deleted;
+ stats.data_file_length+= file->stats.data_file_length;
+ stats.index_file_length+= file->stats.index_file_length;
+ stats.delete_length+= file->stats.delete_length;
+ if (file->stats.check_time > stats.check_time)
+ stats.check_time= file->stats.check_time;
}
} while (*(++file_array));
- if (records < 2 &&
- m_table_flags & HA_NOT_EXACT_COUNT)
- records= 2;
- if (records > 0)
- mean_rec_length= (ulong) (data_file_length / records);
+ if (stats.records < 2 &&
+ !(m_table_flags & HA_STATS_RECORDS_IS_EXACT))
+ stats.records= 2;
+ if (stats.records > 0)
+ stats.mean_rec_length= (ulong) (stats.data_file_length / stats.records);
else
- mean_rec_length= 1; //? What should we set here
+ stats.mean_rec_length= 1; //? What should we set here
}
if (flag & HA_STATUS_CONST)
{
@@ -4255,7 +4245,6 @@ void ha_partition::info(uint flag)
We ignore it since it is never used
block_size: Block size used
We set it to the value of the first handler
- sortkey: Never used at any place so ignored
ref_length: We set this to the value calculated
and stored in local object
create_time: Creation time of table
@@ -4267,7 +4256,7 @@ void ha_partition::info(uint flag)
file= m_file[0];
file->info(HA_STATUS_CONST);
- create_time= file->create_time;
+ stats.create_time= file->stats.create_time;
ref_length= m_ref_length;
}
if (flag & HA_STATUS_ERRKEY)
@@ -4291,14 +4280,14 @@ void ha_partition::info(uint flag)
Used by SHOW commands
We will report the maximum of these times
*/
- update_time= 0;
+ stats.update_time= 0;
file_array= m_file;
do
{
file= *file_array;
file->info(HA_STATUS_TIME);
- if (file->update_time > update_time)
- update_time= file->update_time;
+ if (file->stats.update_time > stats.update_time)
+ stats.update_time= file->stats.update_time;
} while (*(++file_array));
}
DBUG_VOID_RETURN;
@@ -4312,17 +4301,17 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
file->info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK);
- stat_info->records= file->records;
- stat_info->mean_rec_length= file->mean_rec_length;
- stat_info->data_file_length= file->data_file_length;
- stat_info->max_data_file_length= file->max_data_file_length;
- stat_info->index_file_length= file->index_file_length;
- stat_info->delete_length= file->delete_length;
- stat_info->create_time= file->create_time;
- stat_info->update_time= file->update_time;
- stat_info->check_time= file->check_time;
+ stat_info->records= file->stats.records;
+ stat_info->mean_rec_length= file->stats.mean_rec_length;
+ stat_info->data_file_length= file->stats.data_file_length;
+ stat_info->max_data_file_length= file->stats.max_data_file_length;
+ stat_info->index_file_length= file->stats.index_file_length;
+ stat_info->delete_length= file->stats.delete_length;
+ stat_info->create_time= file->stats.create_time;
+ stat_info->update_time= file->stats.update_time;
+ stat_info->check_time= file->stats.check_time;
stat_info->check_sum= 0;
- if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & HA_HAS_CHECKSUM)
stat_info->check_sum= file->checksum();
return;
}
@@ -4393,22 +4382,6 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
2) Parameters used by some non-MyISAM handlers
----------------------------------------------
- HA_EXTRA_RETRIEVE_ALL_COLS:
- Many handlers have implemented optimisations to avoid fetching all
- fields when retrieving data. In certain situations all fields need
- to be retrieved even though the query_id is not set on all field
- objects.
-
- It is called from copy_data_between_tables where all fields are
- copied without setting query_id before calling the handlers.
- It is called from UPDATE statements when the fields of the index
- used is updated or ORDER BY is used with UPDATE.
- And finally when calculating checksum of a table using the CHECKSUM
- command.
- HA_EXTRA_RETRIEVE_PRIMARY_KEY:
- In some situations it is mandatory to retrieve primary key fields
- independent of the query id's. This extra flag specifies that fetch
- of primary key fields is mandatory.
HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
This is a strictly InnoDB feature that is more or less undocumented.
When it is activated InnoDB copies field by field from its fetch
@@ -4557,7 +4530,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
4) Parameters only used by temporary tables for query processing
----------------------------------------------------------------
HA_EXTRA_RESET_STATE:
- Same as HA_EXTRA_RESET except that buffers are not released. If there is
+ Same as reset() except that buffers are not released. If there is
a READ CACHE it is reinit'ed. A cache is reinit'ed to restart reading
or to change type of cache between READ CACHE and WRITE CACHE.
@@ -4596,8 +4569,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
HA_EXTRA_FLUSH_CACHE:
Flush WRITE CACHE in MyISAM. It is only from one place in the code.
This is in sql_insert.cc where it is called if the table_flags doesn't
- contain HA_DUPP_POS. The only handler having the HA_DUPP_POS set is the
- MyISAM handler and so the only handler not receiving this call is MyISAM.
+ contain HA_DUPLICATE_POS. The only handler having the HA_DUPLICATE_POS
+ set is the MyISAM handler and so the only handler not receiving this
+ call is MyISAM.
Thus in effect this call is called but never used. Could be removed
from sql_insert.cc
HA_EXTRA_NO_USER_CHANGE:
@@ -4641,8 +4615,6 @@ int ha_partition::extra(enum ha_extra_function operation)
/* Category 2), used by non-MyISAM handlers */
case HA_EXTRA_IGNORE_DUP_KEY:
case HA_EXTRA_NO_IGNORE_DUP_KEY:
- case HA_EXTRA_RETRIEVE_ALL_COLS:
- case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
{
if (!m_myisam)
@@ -4708,8 +4680,7 @@ int ha_partition::extra(enum ha_extra_function operation)
0 Success
DESCRIPTION
- This will in the future be called instead of extra(HA_EXTRA_RESET) as this
- is such a common call
+ Called at end of each statement to reste buffers
*/
int ha_partition::reset(void)
@@ -5117,14 +5088,16 @@ void ha_partition::print_error(int error, myf errflag)
/* Should probably look for my own errors first */
/* monty: needs to be called for the last used partition ! */
- DBUG_PRINT("enter", ("error = %d", error));
+ DBUG_PRINT("enter", ("error: %d", error));
if (error == HA_ERR_NO_PARTITION_FOUND)
{
char buf[100];
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0),
m_part_info->part_expr->null_value ? "NULL" :
llstr(m_part_info->part_expr->val_int(), buf));
+ dbug_tmp_restore_column_map(table->read_set, old_map);
}
else
m_file[0]->print_error(error, errflag);
@@ -5304,19 +5277,55 @@ void ha_partition::restore_auto_increment()
partitions.
*/
-ulonglong ha_partition::get_auto_increment()
+void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
- ulonglong auto_inc, max_auto_inc= 0;
+ ulonglong first_value_part, last_value_part, nb_reserved_values_part,
+ last_value= ~ (ulonglong) 0;
+ handler **pos, **end;
DBUG_ENTER("ha_partition::get_auto_increment");
- for (uint i= 0; i < m_tot_parts; i++)
+ for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
+ {
+ (*pos)->get_auto_increment(offset, increment, nb_desired_values,
+ &first_value_part, &nb_reserved_values_part);
+ if (first_value_part == ~(ulonglong)(0)) // error in one partition
+ {
+ *first_value= first_value_part;
+ break;
+ }
+ /*
+ Partition has reserved an interval. Intersect it with the intervals
+ already reserved for the previous partitions.
+ */
+ last_value_part= (nb_reserved_values_part == ULONGLONG_MAX) ?
+ ULONGLONG_MAX : (first_value_part + nb_reserved_values_part * increment);
+ set_if_bigger(*first_value, first_value_part);
+ set_if_smaller(last_value, last_value_part);
+ }
+ if (last_value < *first_value) /* empty intersection, error */
{
- auto_inc= m_file[i]->get_auto_increment();
- set_if_bigger(max_auto_inc, auto_inc);
+ *first_value= ~(ulonglong)(0);
}
- DBUG_RETURN(max_auto_inc);
+ if (increment) // If not check for values
+ *nb_reserved_values= (last_value == ULONGLONG_MAX) ?
+ ULONGLONG_MAX : ((last_value - *first_value) / increment);
+
+ DBUG_VOID_RETURN;
}
+void ha_partition::release_auto_increment()
+{
+ DBUG_ENTER("ha_partition::release_auto_increment");
+
+ for (uint i= 0; i < m_tot_parts; i++)
+ {
+ m_file[i]->release_auto_increment();
+ }
+ DBUG_VOID_RETURN;
+}
/****************************************************************************
MODULE initialise handler for HANDLER call
@@ -5525,15 +5534,17 @@ static int free_share(PARTITION_SHARE *share)
}
#endif /* NOT_USED */
+struct st_mysql_storage_engine partition_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &partition_hton };
mysql_declare_plugin(partition)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &partition_hton,
- partition_hton_name,
+ &partition_storage_engine,
+ "partition",
"Mikael Ronstrom, MySQL AB",
- partition_hton_comment,
- NULL, /* Plugin Init */
+ "Partition Storage Engine Helper",
+ partition_initialize, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100, /* 1.0 */
0
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 1443a20133c..b52c8d92164 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -95,7 +95,6 @@ private:
uint m_rec_length; // Local copy of record length
bool m_ordered; // Ordered/Unordered index scan
- bool m_has_transactions; // Can we support transactions
bool m_pkey_is_clustered; // Is primary key clustered
bool m_create_handler; // Handler used to create table
bool m_is_sub_partitioned; // Is subpartitioned
@@ -157,7 +156,7 @@ public:
enable later calls of the methods to retrieve constants from the under-
lying handlers. Returns false if not successful.
*/
- int ha_initialise();
+ bool initialise_partition(MEM_ROOT *mem_root);
/*
-------------------------------------------------------------------------
@@ -208,25 +207,24 @@ private:
delete_table, rename_table and create uses very similar logic which
is packed into this routine.
*/
- uint del_ren_cre_table(const char *from,
- const char *to= NULL,
- TABLE *table_arg= NULL,
- HA_CREATE_INFO *create_info= NULL);
+ uint del_ren_cre_table(const char *from, const char *to,
+ TABLE *table_arg, HA_CREATE_INFO *create_info);
/*
One method to create the table_name.par file containing the names of the
underlying partitions, their engine and the number of partitions.
And one method to read it in.
*/
bool create_handler_file(const char *name);
- bool get_from_handler_file(const char *name);
- bool new_handlers_from_part_info();
- bool create_handlers();
+ bool get_from_handler_file(const char *name, MEM_ROOT *mem_root);
+ bool new_handlers_from_part_info(MEM_ROOT *mem_root);
+ bool create_handlers(MEM_ROOT *mem_root);
void clear_handler_file();
void set_up_table_before_create(TABLE *table_arg,
const char *partition_name_with_path,
HA_CREATE_INFO *info,
uint part_id);
partition_element *find_partition_element(uint part_id);
+
public:
/*
@@ -588,7 +586,7 @@ public:
NULLable field.
(BDB, HEAP, MyISAM, NDB, InnoDB)
- HA_DUPP_POS:
+ HA_DUPLICATE_POS:
Tells that we can the position for the conflicting duplicate key
record is stored in table->file->dupp_ref. (insert uses rnd_pos() on
this to find the duplicated row)
@@ -609,11 +607,10 @@ public:
with hidden primary key)
(No handler has this limitation currently)
- HA_NOT_EXACT_COUNT:
+ HA_STATS_RECORDS_IS_EXACT:
Does the counter of records after the info call specify an exact
- value or not. If it doesn't this flag is set.
+ value or not. If it does this flag is set.
Only MyISAM and HEAP uses exact count.
- (MyISAM, HEAP, BDB, InnoDB, NDB, Federated)
HA_CAN_INSERT_DELAYED:
Can the storage engine support delayed inserts.
@@ -676,7 +673,7 @@ public:
index scan module.
(NDB)
*/
- virtual ulong table_flags() const
+ virtual ulonglong table_flags() const
{ return m_table_flags; }
/*
@@ -771,13 +768,6 @@ public:
virtual uint min_record_length(uint options) const;
/*
- Transactions on the table is supported if all handlers below support
- transactions.
- */
- virtual bool has_transactions()
- { return m_has_transactions; }
-
- /*
Primary key is clustered can only be true if all underlying handlers have
this feature.
*/
@@ -815,7 +805,11 @@ public:
-------------------------------------------------------------------------
*/
virtual void restore_auto_increment();
- virtual ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
+ virtual void release_auto_increment();
/*
-------------------------------------------------------------------------
diff --git a/sql/handler.cc b/sql/handler.cc
index b9ef05a33c2..81c42f9da15 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -44,48 +44,29 @@
#include "ha_innodb.h"
#endif
-/* While we have legacy_db_type, we have this array to
- check for dups and to find handlerton from legacy_db_type.
- Remove when legacy_db_type is finally gone */
-static handlerton *installed_htons[128];
+/*
+ While we have legacy_db_type, we have this array to
+ check for dups and to find handlerton from legacy_db_type.
+ Remove when legacy_db_type is finally gone
+*/
+st_plugin_int *hton2plugin[MAX_HA];
-#define BITMAP_STACKBUF_SIZE (128/8)
+static handlerton *installed_htons[128];
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
/* static functions defined in this file */
-static handler *create_default(TABLE_SHARE *table);
-
-const handlerton default_hton =
-{
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- "DEFAULT",
- SHOW_OPTION_YES,
- NULL,
- DB_TYPE_DEFAULT,
- NULL,
- 0, 0,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
- create_default,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, /* alter_tablespace */
- NULL, /* fill_files_table */
- HTON_NO_FLAGS, /* flags */
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
+static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root);
static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
/* number of entries in handlertons[] */
-ulong total_ha;
+ulong total_ha= 0;
/* number of storage engines (from handlertons[]) that support 2pc */
-ulong total_ha_2pc;
+ulong total_ha_2pc= 0;
/* size of savepoint storage area (see ha_init) */
-ulong savepoint_alloc_size;
+ulong savepoint_alloc_size= 0;
struct show_table_alias_st sys_table_aliases[]=
{
@@ -122,7 +103,7 @@ handlerton *ha_resolve_by_name(THD *thd, LEX_STRING *name)
if ((plugin= plugin_lock(name, MYSQL_STORAGE_ENGINE_PLUGIN)))
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (!(hton->flags & HTON_NOT_USER_SELECTABLE))
return hton;
plugin_unlock(plugin);
@@ -146,8 +127,7 @@ handlerton *ha_resolve_by_name(THD *thd, LEX_STRING *name)
const char *ha_get_storage_engine(enum legacy_db_type db_type)
{
- switch (db_type)
- {
+ switch (db_type) {
case DB_TYPE_DEFAULT:
return "DEFAULT";
case DB_TYPE_UNKNOWN:
@@ -155,24 +135,22 @@ const char *ha_get_storage_engine(enum legacy_db_type db_type)
default:
if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
installed_htons[db_type])
- return installed_htons[db_type]->name;
+ return hton2plugin[installed_htons[db_type]->slot]->name.str;
return "*NONE*";
}
}
-static handler *create_default(TABLE_SHARE *table)
+static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
handlerton *hton=ha_resolve_by_legacy_type(current_thd, DB_TYPE_DEFAULT);
- return (hton && hton != &default_hton && hton->create) ?
- hton->create(table) : NULL;
+ return (hton && hton->create) ? hton->create(table, mem_root) : NULL;
}
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
{
- switch (db_type)
- {
+ switch (db_type) {
case DB_TYPE_DEFAULT:
return (thd->variables.table_type != NULL) ?
thd->variables.table_type :
@@ -183,7 +161,7 @@ handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
default:
if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT)
return installed_htons[db_type];
- return NULL;
+ return NULL;
}
}
@@ -225,36 +203,23 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
handlerton *db_type)
{
- handler *file= NULL;
- /*
- handlers are allocated with new in the handlerton create() function
- we need to set the thd mem_root for these to be allocated correctly
- */
- THD *thd= current_thd;
- MEM_ROOT *thd_save_mem_root= thd->mem_root;
- thd->mem_root= alloc;
-
- if (db_type != NULL && db_type->state == SHOW_OPTION_YES && db_type->create)
- file= db_type->create(share);
-
- thd->mem_root= thd_save_mem_root;
+ handler *file;
+ DBUG_ENTER("get_new_handler");
+ DBUG_PRINT("enter", ("alloc: 0x%lx", (long) alloc));
- if (!file)
- {
- handlerton *def= current_thd->variables.table_type;
- /* Try first with 'default table type' */
- if (db_type != def)
- return get_new_handler(share, alloc, def);
- }
- if (file)
+ if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
{
- if (file->ha_initialise())
- {
- delete file;
- file=0;
- }
+ if ((file= db_type->create(share, alloc)))
+ file->init();
+ DBUG_RETURN(file);
}
- return file;
+ /*
+ Try the default table type
+ Here the call to current_thd() is ok as we call this function a lot of
+ times but we enter this branch very seldom.
+ */
+ DBUG_RETURN(get_new_handler(share, alloc,
+ current_thd->variables.table_type));
}
@@ -265,11 +230,13 @@ handler *get_ha_partition(partition_info *part_info)
DBUG_ENTER("get_ha_partition");
if ((partition= new ha_partition(part_info)))
{
- if (partition->ha_initialise())
+ if (partition->initialise_partition(current_thd->mem_root))
{
delete partition;
partition= 0;
}
+ else
+ partition->init();
}
else
{
@@ -372,22 +339,19 @@ static int ha_finish_errors(void)
int ha_finalize_handlerton(st_plugin_int *plugin)
{
- handlerton *hton;
+ handlerton *hton= (handlerton *)plugin->data;
DBUG_ENTER("ha_finalize_handlerton");
- if (!(hton= (handlerton *) plugin->plugin->info))
- DBUG_RETURN(1);
-
switch (hton->state)
{
case SHOW_OPTION_NO:
case SHOW_OPTION_DISABLED:
break;
case SHOW_OPTION_YES:
- if (hton->panic && hton->panic(HA_PANIC_CLOSE))
- DBUG_RETURN(1);
if (installed_htons[hton->db_type] == hton)
installed_htons[hton->db_type]= NULL;
+ if (hton->panic && hton->panic(HA_PANIC_CLOSE))
+ DBUG_RETURN(1);
break;
};
DBUG_RETURN(0);
@@ -396,37 +360,28 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
int ha_initialize_handlerton(st_plugin_int *plugin)
{
- handlerton *hton;
+ handlerton *hton= ((st_mysql_storage_engine *)plugin->plugin->info)->handlerton;
DBUG_ENTER("ha_initialize_handlerton");
- if (!(hton= (handlerton *) plugin->plugin->info))
- DBUG_RETURN(1);
-
- /* for the sake of sanity, we set the handlerton name to be the
- same as the plugin name */
- hton->name= plugin->name.str;
-
+ plugin->data= hton; // shortcut for the future
+ /*
+ the switch below and hton->state should be removed when
+ command-line options for plugins will be implemented
+ */
switch (hton->state) {
case SHOW_OPTION_NO:
break;
case SHOW_OPTION_YES:
- if (!hton->init || !hton->init())
{
- uint tmp= hton->savepoint_offset;
- hton->savepoint_offset= savepoint_alloc_size;
- savepoint_alloc_size+= tmp;
- hton->slot= total_ha++;
- if (hton->prepare)
- total_ha_2pc++;
-
+ uint tmp;
/* now check the db_type for conflict */
- if (hton->db_type <= DB_TYPE_UNKNOWN ||
+ if (hton->db_type <= DB_TYPE_UNKNOWN ||
hton->db_type >= DB_TYPE_DEFAULT ||
installed_htons[hton->db_type])
{
int idx= (int) DB_TYPE_FIRST_DYNAMIC;
-
+
while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
idx++;
@@ -437,10 +392,17 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
}
if (hton->db_type != DB_TYPE_UNKNOWN)
sql_print_warning("Storage engine '%s' has conflicting typecode. "
- "Assigning value %d.", hton->name, idx);
+ "Assigning value %d.", plugin->plugin->name, idx);
hton->db_type= (enum legacy_db_type) idx;
}
installed_htons[hton->db_type]= hton;
+ tmp= hton->savepoint_offset;
+ hton->savepoint_offset= savepoint_alloc_size;
+ savepoint_alloc_size+= tmp;
+ hton->slot= total_ha++;
+ hton2plugin[hton->slot]=plugin;
+ if (hton->prepare)
+ total_ha_2pc++;
break;
}
/* fall through */
@@ -451,33 +413,14 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
DBUG_RETURN(0);
}
-
-static my_bool init_handlerton(THD *unused1, st_plugin_int *plugin,
- void *unused2)
-{
- if (plugin->state == PLUGIN_IS_UNINITIALIZED)
- {
- ha_initialize_handlerton(plugin);
- plugin->state= PLUGIN_IS_READY;
- }
- return FALSE;
-}
-
-
int ha_init()
{
int error= 0;
- total_ha= savepoint_alloc_size= 0;
DBUG_ENTER("ha_init");
- bzero(installed_htons, sizeof(installed_htons));
-
if (ha_init_errors())
DBUG_RETURN(1);
- if (plugin_foreach(NULL, init_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0))
- DBUG_RETURN(1);
-
DBUG_ASSERT(total_ha < MAX_HA);
/*
Check if there is a transaction-capable storage engine besides the
@@ -489,16 +432,14 @@ int ha_init()
DBUG_RETURN(error);
}
+/*
+ close, flush or restart databases
+ Ignore this for other databases than ours
+*/
-
-
- /* close, flush or restart databases */
- /* Ignore this for other databases than ours */
-
-static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin,
- void *arg)
+static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin, void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->panic)
((int*)arg)[0]|= hton->panic((enum ha_panic_function)((int*)arg)[1]);
return FALSE;
@@ -508,10 +449,10 @@ static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin,
int ha_panic(enum ha_panic_function flag)
{
int error[2];
-
+
error[0]= 0; error[1]= (int)flag;
plugin_foreach(NULL, panic_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, error);
-
+
if (flag == HA_PANIC_CLOSE && ha_finish_errors())
error[0]= 1;
return error[0];
@@ -520,7 +461,7 @@ int ha_panic(enum ha_panic_function flag)
static my_bool dropdb_handlerton(THD *unused1, st_plugin_int *plugin,
void *path)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->drop_database)
hton->drop_database((char *)path);
return FALSE;
@@ -536,9 +477,11 @@ void ha_drop_database(char* path)
static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin,
void *unused)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
- /* there's no need to rollback here as all transactions must
- be rolled back already */
+ handlerton *hton= (handlerton *)plugin->data;
+ /*
+ there's no need to rollback here as all transactions must
+ be rolled back already
+ */
if (hton->state == SHOW_OPTION_YES && hton->close_connection &&
thd->ha_data[hton->slot])
hton->close_connection(thd);
@@ -628,7 +571,8 @@ int ha_prepare(THD *thd)
else
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), (*ht)->name);
+ ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
+ hton2plugin[(*ht)->slot]->name.str);
}
}
}
@@ -867,7 +811,7 @@ struct xahton_st {
static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin,
void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->commit_by_xid(((struct xahton_st *)arg)->xid);
@@ -879,7 +823,7 @@ static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin,
static my_bool xarollback_handlerton(THD *unused1, st_plugin_int *plugin,
void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->rollback_by_xid(((struct xahton_st *)arg)->xid);
@@ -894,7 +838,7 @@ int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
struct xahton_st xaop;
xaop.xid= xid;
xaop.result= 1;
-
+
plugin_foreach(NULL, commit ? xacommit_handlerton : xarollback_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &xaop);
@@ -986,16 +930,16 @@ struct xarecover_st
static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
struct xarecover_st *info= (struct xarecover_st *) arg;
int got;
-
+
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
while ((got= hton->recover(info->list, info->len)) > 0 )
{
sql_print_information("Found %d prepared transaction(s) in %s",
- got, hton->name);
+ got, hton2plugin[hton->slot]->name.str);
for (int i=0; i < got; i ++)
{
my_xid x=info->list[i].get_my_xid();
@@ -1175,7 +1119,7 @@ bool mysql_xa_recover(THD *thd)
static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin,
void *unused)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
hton->release_temporary_latches(thd);
@@ -1300,7 +1244,7 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
static my_bool snapshot_handlerton(THD *thd, st_plugin_int *plugin,
void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES &&
hton->start_consistent_snapshot)
{
@@ -1331,7 +1275,7 @@ int ha_start_consistent_snapshot(THD *thd)
static my_bool flush_handlerton(THD *thd, st_plugin_int *plugin,
void *arg)
{
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->flush_logs && hton->flush_logs())
return TRUE;
return FALSE;
@@ -1379,7 +1323,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
! (file=get_new_handler(&dummy_share, thd->mem_root, table_type)))
DBUG_RETURN(ENOENT);
- if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
+ if (lower_case_table_names == 2 && !(file->ha_table_flags() & HA_FILE_BASED))
{
/* Ensure that table handler get path in lower case */
strmov(tmp_path, path);
@@ -1462,6 +1406,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
table= table_arg;
DBUG_ASSERT(table->s == table_share);
+ DBUG_ASSERT(alloc_root_inited(&table->mem_root));
if ((error=open(name,mode,test_if_locked)))
{
@@ -1483,106 +1428,23 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
- DBUG_ASSERT(alloc_root_inited(&table->mem_root));
-
if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
{
close();
error=HA_ERR_OUT_OF_MEM;
}
else
- dupp_ref=ref+ALIGN_SIZE(ref_length);
-
- if (ha_allocate_read_write_set(table->s->fields))
- error= 1;
+ dup_ref=ref+ALIGN_SIZE(ref_length);
+ cached_table_flags= table_flags();
}
DBUG_RETURN(error);
}
-int handler::ha_initialise()
-{
- DBUG_ENTER("ha_initialise");
- DBUG_RETURN(FALSE);
-}
-
-
-/*
- Initalize bit maps for used fields
-
- Called from open_table_from_share()
-*/
-
-int handler::ha_allocate_read_write_set(ulong no_fields)
-{
- uint bitmap_size= bitmap_buffer_size(no_fields+1);
- uint32 *read_buf, *write_buf;
- DBUG_ENTER("ha_allocate_read_write_set");
- DBUG_PRINT("enter", ("no_fields = %d", no_fields));
-
- if (!multi_alloc_root(&table->mem_root,
- &read_set, sizeof(MY_BITMAP),
- &write_set, sizeof(MY_BITMAP),
- &read_buf, bitmap_size,
- &write_buf, bitmap_size,
- NullS))
- {
- DBUG_RETURN(TRUE);
- }
- bitmap_init(read_set, read_buf, no_fields+1, FALSE);
- bitmap_init(write_set, write_buf, no_fields+1, FALSE);
- table->read_set= read_set;
- table->write_set= write_set;
- ha_clear_all_set();
- DBUG_RETURN(FALSE);
-}
-
-void handler::ha_clear_all_set()
-{
- DBUG_ENTER("ha_clear_all_set");
- bitmap_clear_all(read_set);
- bitmap_clear_all(write_set);
- bitmap_set_bit(read_set, 0);
- bitmap_set_bit(write_set, 0);
- DBUG_VOID_RETURN;
-}
-
-int handler::ha_retrieve_all_cols()
-{
- DBUG_ENTER("handler::ha_retrieve_all_cols");
- bitmap_set_all(read_set);
- DBUG_RETURN(0);
-}
-
-int handler::ha_retrieve_all_pk()
-{
- DBUG_ENTER("ha_retrieve_all_pk");
- ha_set_primary_key_in_read_set();
- DBUG_RETURN(0);
-}
-
-void handler::ha_set_primary_key_in_read_set()
-{
- ulong prim_key= table->s->primary_key;
- DBUG_ENTER("handler::ha_set_primary_key_in_read_set");
- DBUG_PRINT("info", ("Primary key = %d", prim_key));
- if (prim_key != MAX_KEY)
- {
- KEY_PART_INFO *key_part= table->key_info[prim_key].key_part;
- KEY_PART_INFO *key_part_end= key_part +
- table->key_info[prim_key].key_parts;
- for (;key_part != key_part_end; ++key_part)
- ha_set_bit_in_read_set(key_part->fieldnr);
- }
- DBUG_VOID_RETURN;
-}
-
-
-
/*
Read first row (only) from a table
This is never called for InnoDB or BDB tables, as these table types
- has the HA_NOT_EXACT_COUNT set.
+ has the HA_STATS_RECORDS_IS_EXACT set.
*/
int handler::read_first_row(byte * buf, uint primary_key)
@@ -1598,7 +1460,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
scanning the table.
TODO remove the test for HA_READ_ORDER
*/
- if (deleted < 10 || primary_key >= MAX_KEY ||
+ if (stats.deleted < 10 || primary_key >= MAX_KEY ||
!(index_flags(primary_key, 0, 0) & HA_READ_ORDER))
{
(void) ha_rnd_init(1);
@@ -1639,7 +1501,7 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
Update the auto_increment field if necessary
SYNOPSIS
- update_auto_increment()
+ update_auto_increment()
RETURN
0 ok
@@ -1668,8 +1530,9 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
statement. For the following rows we generate new numbers based on the
last used number.
- - thd->next_insert_id != 0. This happens when we have read a statement
- from the binary log or when one has used SET LAST_INSERT_ID=#.
+ - thd->next_insert_id != 0. This happens when we have read an Intvar event
+ of type INSERT_ID_EVENT from the binary log or when one has used SET
+ INSERT_ID=#.
In this case we will set the column to the value of next_insert_id.
The next row will be given the id
@@ -1685,8 +1548,20 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
start counting from the inserted value.
thd->next_insert_id is cleared after it's been used for a statement.
+
+ TODO
+
+ Replace all references to "next number" or NEXT_NUMBER to
+ "auto_increment", everywhere (see below: there is
+ table->auto_increment_field_not_null, and there also exists
+ table->next_number_field, it's not consistent).
+
*/
+#define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here
+#define AUTO_INC_DEFAULT_NB_MAX_BITS 16
+#define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1)
+
bool handler::update_auto_increment()
{
ulonglong nr;
@@ -1702,17 +1577,24 @@ bool handler::update_auto_increment()
*/
thd->prev_insert_id= thd->next_insert_id;
auto_increment_field_not_null= table->auto_increment_field_not_null;
- table->auto_increment_field_not_null= FALSE;
+ table->auto_increment_field_not_null= FALSE; // to reset for next row
if ((nr= table->next_number_field->val_int()) != 0 ||
auto_increment_field_not_null &&
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
{
- /* Clear flag for next row */
- /* Mark that we didn't generate a new value **/
+ /*
+ The user did specify a value for the auto_inc column, we don't generate
+ a new value, write it down.
+ */
auto_increment_column_changed=0;
- /* Update next_insert_id if we have already generated a value */
+ /*
+ Update next_insert_id if we had already generated a value in this
+ statement (case of INSERT VALUES(null),(3763),(null):
+ the last NULL needs to insert 3764, not the value of the first NULL plus
+ 1).
+ */
if (thd->clear_next_insert_id && nr >= thd->next_insert_id)
{
if (variables->auto_increment_increment != 1)
@@ -1726,9 +1608,53 @@ bool handler::update_auto_increment()
}
if (!(nr= thd->next_insert_id))
{
- if ((nr= get_auto_increment()) == ~(ulonglong) 0)
+ ulonglong nb_desired_values= 1, nb_reserved_values;
+#ifdef TO_BE_ENABLED_SOON
+ /*
+ Reserved intervals will be stored in "THD::auto_inc_intervals".
+ handler::estimation_rows_to_insert will be the argument passed by
+ handler::ha_start_bulk_insert().
+ */
+ uint estimation_known= test(estimation_rows_to_insert > 0);
+ uint nb_already_reserved_intervals= thd->auto_inc_intervals.nb_elements();
+ /*
+ If an estimation was given to the engine:
+ - use it.
+ - if we already reserved numbers, it means the estimation was
+ not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_VALUES the 2nd
+ time, twice that the 3rd time etc.
+ If no estimation was given, use those increasing defaults from the
+ start, starting from AUTO_INC_DEFAULT_NB_VALUES.
+ Don't go beyond a max to not reserve "way too much" (because reservation
+ means potentially losing unused values).
+ */
+ if (nb_already_reserved_intervals == 0 && estimation_known)
+ nb_desired_values= estimation_rows_to_insert;
+ else /* go with the increasing defaults */
+ {
+ /* avoid overflow in formula, with this if() */
+ if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS)
+ {
+ nb_desired_values= AUTO_INC_DEFAULT_NB_VALUES *
+ (1 << nb_already_reserved_intervals);
+ set_if_smaller(nb_desired_values, AUTO_INC_DEFAULT_NB_MAX);
+ }
+ else
+ nb_desired_values= AUTO_INC_DEFAULT_NB_MAX;
+ }
+#endif
+ /* This call ignores all its parameters but nr, currently */
+ get_auto_increment(variables->auto_increment_offset,
+ variables->auto_increment_increment,
+ nb_desired_values, &nr,
+ &nb_reserved_values);
+ if (nr == ~(ulonglong) 0)
result= 1; // Mark failure
+ /*
+ That should not be needed when engines actually use offset and increment
+ above.
+ */
if (variables->auto_increment_increment != 1)
nr= next_insert_id(nr-1, variables);
/*
@@ -1786,16 +1712,69 @@ void handler::restore_auto_increment()
}
-ulonglong handler::get_auto_increment()
+/*
+ MySQL signal that it changed the column bitmap
+
+ USAGE
+ This is for handlers that needs to setup their own column bitmaps.
+ Normally the handler should set up their own column bitmaps in
+ index_init() or rnd_init() and in any column_bitmaps_signal() call after
+ this.
+
+ The handler is allowd to do changes to the bitmap after a index_init or
+ rnd_init() call is made as after this, MySQL will not use the bitmap
+ for any program logic checking.
+*/
+
+void handler::column_bitmaps_signal()
+{
+ DBUG_ENTER("column_bitmaps_signal");
+ DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx", table->read_set,
+ table->write_set));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Reserves an interval of auto_increment values from the handler.
+
+ SYNOPSIS
+ get_auto_increment()
+ offset
+ increment
+ nb_desired_values how many values we want
+ first_value (OUT) the first value reserved by the handler
+ nb_reserved_values (OUT) how many values the handler reserved
+
+ offset and increment means that we want values to be of the form
+ offset + N * increment, where N>=0 is integer.
+ If the function sets *first_value to ~(ulonglong)0 it means an error.
+ If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has
+ reserved to "positive infinite".
+*/
+
+void handler::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
ulonglong nr;
int error;
(void) extra(HA_EXTRA_KEYREAD);
+ table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
+ table->read_set);
+ column_bitmaps_signal();
index_init(table->s->next_number_index, 1);
if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
+ /*
+ MySQL implicitely assumes such method does locking (as MySQL decides to
+ use nr+increment without checking again with the handler, in
+ handler::update_auto_increment()), so reserves to infinite.
+ */
+ *nb_reserved_values= ULONGLONG_MAX;
}
else
{
@@ -1805,6 +1784,13 @@ ulonglong handler::get_auto_increment()
table->s->next_number_key_offset);
error= index_read(table->record[1], key, table->s->next_number_key_offset,
HA_READ_PREFIX_LAST);
+ /*
+ 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;
}
if (error)
@@ -1814,7 +1800,25 @@ ulonglong handler::get_auto_increment()
val_int_offset(table->s->rec_buff_length)+1);
index_end();
(void) extra(HA_EXTRA_NO_KEYREAD);
- return nr;
+ *first_value= nr;
+}
+
+
+void handler::print_keydup_error(uint key_nr, const char *msg)
+{
+ /* Write the duplicated key in the error message */
+ char key[MAX_KEY_LENGTH];
+ String str(key,sizeof(key),system_charset_info);
+ /* Table is opened and defined at this point */
+ key_unpack(&str,table,(uint) key_nr);
+ uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(msg);
+ if (str.length() >= max_length)
+ {
+ str.length(max_length-4);
+ str.append(STRING_WITH_LEN("..."));
+ }
+ my_printf_error(ER_DUP_ENTRY, msg,
+ MYF(0), str.c_ptr(), table->key_info[key_nr].name);
}
@@ -1857,18 +1861,7 @@ void handler::print_error(int error, myf errflag)
uint key_nr=get_dup_key(error);
if ((int) key_nr >= 0)
{
- /* Write the duplicated key in the error message */
- char key[MAX_KEY_LENGTH];
- String str(key,sizeof(key),system_charset_info);
- /* Table is opened and defined at this point */
- key_unpack(&str,table,(uint) key_nr);
- uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY));
- if (str.length() >= max_length)
- {
- str.length(max_length-4);
- str.append(STRING_WITH_LEN("..."));
- }
- my_error(ER_DUP_ENTRY, MYF(0), str.c_ptr(), table->key_info[key_nr].name);
+ print_keydup_error(key_nr, ER(ER_DUP_ENTRY));
DBUG_VOID_RETURN;
}
textno=ER_DUP_KEY;
@@ -1879,12 +1872,14 @@ void handler::print_error(int error, myf errflag)
uint key_nr= get_dup_key(error);
if ((int) key_nr >= 0)
{
+ uint max_length;
/* Write the key in the error message */
char key[MAX_KEY_LENGTH];
String str(key,sizeof(key),system_charset_info);
/* Table is opened and defined at this point */
key_unpack(&str,table,(uint) key_nr);
- uint max_length= MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY));
+ max_length= (MYSQL_ERRMSG_SIZE-
+ (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
if (str.length() >= max_length)
{
str.length(max_length-4);
@@ -2293,22 +2288,23 @@ int handler::index_next_same(byte *buf, const byte *key, uint keylen)
}
-void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id)
+void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+ uint part_id)
{
info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK);
- stat_info->records= records;
- stat_info->mean_rec_length= mean_rec_length;
- stat_info->data_file_length= data_file_length;
- stat_info->max_data_file_length= max_data_file_length;
- stat_info->index_file_length= index_file_length;
- stat_info->delete_length= delete_length;
- stat_info->create_time= create_time;
- stat_info->update_time= update_time;
- stat_info->check_time= check_time;
- stat_info->check_sum= 0;
+ stat_info->records= stats.records;
+ stat_info->mean_rec_length= stats.mean_rec_length;
+ stat_info->data_file_length= stats.data_file_length;
+ stat_info->max_data_file_length= stats.max_data_file_length;
+ stat_info->index_file_length= stats.index_file_length;
+ stat_info->delete_length= stats.delete_length;
+ stat_info->create_time= stats.create_time;
+ 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)
- stat_info->check_sum= checksum();
+ stat_info->check_sum= checksum();
return;
}
@@ -2318,11 +2314,11 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id
****************************************************************************/
/*
- Initiates table-file and calls apropriate database-creator
+ Initiates table-file and calls appropriate database-creator
NOTES
We must have a write lock on LOCK_open to be sure no other thread
- interfers with table
+ interferes with table
RETURN
0 ok
@@ -2352,7 +2348,7 @@ int ha_create_table(THD *thd, const char *path,
name= share.path.str;
if (lower_case_table_names == 2 &&
- !(table.file->table_flags() & HA_FILE_BASED))
+ !(table.file->ha_table_flags() & HA_FILE_BASED))
{
/* Ensure that handler gets name in lower case */
strmov(name_buff, name);
@@ -2431,7 +2427,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
if (lower_case_table_names == 2 &&
- !(table.file->table_flags() & HA_FILE_BASED))
+ !(table.file->ha_table_flags() & HA_FILE_BASED))
{
/* Ensure that handler gets name in lower case */
my_casedn_str(files_charset_info, path);
@@ -2566,7 +2562,7 @@ int ha_discover(THD *thd, const char *db, const char *name,
/*
- Call this function in order to give the handler the possiblity
+ Call this function in order to give the handler the possibility
to ask engine if there are any new tables that should be written to disk
or any dropped tables that need to be removed from disk
*/
@@ -2635,7 +2631,7 @@ struct binlog_func_st
static my_bool binlog_func_list(THD *thd, st_plugin_int *plugin, void *arg)
{
hton_list_st *hton_list= (hton_list_st *)arg;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->binlog_func)
{
uint sz= hton_list->sz;
@@ -2725,7 +2721,7 @@ static my_bool binlog_log_query_handlerton(THD *thd,
st_plugin_int *plugin,
void *args)
{
- return binlog_log_query_handlerton2(thd, (const handlerton *) plugin->plugin->info, args);
+ return binlog_log_query_handlerton2(thd, (const handlerton *)plugin->data, args);
}
void ha_binlog_log_query(THD *thd, const handlerton *hton,
@@ -2781,6 +2777,9 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
multi_range_sorted= sorted;
multi_range_buffer= buffer;
+ table->mark_columns_used_by_index_no_reset(active_index, table->read_set);
+ table->column_bitmaps_set(table->read_set, table->write_set);
+
for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
multi_range_curr < multi_range_end;
multi_range_curr++)
@@ -3006,7 +3005,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,
SYNOPSIS
ha_known_exts()
-
+
NOTES
No mutexes, worst case race is a minor surplus memory allocation
We have to recreate the extension map if mysqld is restarted (for example
@@ -3020,14 +3019,14 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
void *arg)
{
List<char> *found_exts= (List<char> *) arg;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
handler *file;
if (hton->state == SHOW_OPTION_YES && hton->create &&
- (file= hton->create((TABLE_SHARE*) 0)))
+ (file= hton->create((TABLE_SHARE*) 0, current_thd->mem_root)))
{
List_iterator_fast<char> it(*found_exts);
const char **ext, *old_ext;
-
+
for (ext= file->bas_ext(); *ext; ext++)
{
while ((old_ext= it++))
@@ -3056,14 +3055,14 @@ TYPELIB *ha_known_exts(void)
known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) triggers_file_ext);
found_exts.push_back((char*) trigname_file_ext);
-
- plugin_foreach(NULL, exts_handlerton,
+
+ plugin_foreach(NULL, exts_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts);
ext= (const char **) my_once_alloc(sizeof(char *)*
(found_exts.elements+1),
MYF(MY_WME | MY_FAE));
-
+
DBUG_ASSERT(ext != 0);
known_extensions.count= found_exts.elements;
known_extensions.type_names= ext;
@@ -3096,7 +3095,7 @@ static my_bool showstat_handlerton(THD *thd, st_plugin_int *plugin,
void *arg)
{
enum ha_stat_type stat= *(enum ha_stat_type *) arg;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (hton->state == SHOW_OPTION_YES && hton->show_status &&
hton->show_status(thd, stat_print, stat))
return TRUE;
@@ -3119,16 +3118,19 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
if (db_type == NULL)
{
- result= plugin_foreach(thd, showstat_handlerton,
+ result= plugin_foreach(thd, showstat_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &stat);
}
else
{
if (db_type->state != SHOW_OPTION_YES)
- result= stat_print(thd, db_type->name, strlen(db_type->name),
+ {
+ const LEX_STRING *name=&hton2plugin[db_type->slot]->name;
+ result= stat_print(thd, name->str, name->length,
"", 0, "DISABLED", 8) ? 1 : 0;
+ }
else
- result= db_type->show_status &&
+ result= db_type->show_status &&
db_type->show_status(thd, stat_print, stat) ? 1 : 0;
}
@@ -3160,7 +3162,7 @@ namespace {
char const *name;
};
- int table_name_compare(void const *a, void const *b)
+ static int table_name_compare(void const *a, void const *b)
{
st_table_data const *x = (st_table_data const*) a;
st_table_data const *y = (st_table_data const*) b;
@@ -3191,44 +3193,29 @@ namespace {
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
table->s->cached_row_logging_check == 1);
- return
- thd->current_stmt_binlog_row_based &&
- thd && (thd->options & OPTION_BIN_LOG) &&
- mysql_bin_log.is_open() &&
- table->s->cached_row_logging_check;
+ return (thd->current_stmt_binlog_row_based &&
+ (thd->options & OPTION_BIN_LOG) &&
+ mysql_bin_log.is_open() &&
+ table->s->cached_row_logging_check);
}
}
-template<class RowsEventT> int binlog_log_row(TABLE* table,
+template<class RowsEventT> int binlog_log_row(TABLE *table,
const byte *before_record,
const byte *after_record)
{
if (table->file->is_injective())
return 0;
bool error= 0;
- THD *const thd= current_thd;
-
- if (check_table_binlog_row_based(thd, table))
- {
- MY_BITMAP cols;
- /* Potential buffer on the stack for the bitmap */
- uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)];
- uint n_fields= table->s->fields;
- my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8;
- if (likely(!(error= bitmap_init(&cols,
- use_bitbuf ? bitbuf : NULL,
- (n_fields + 7) & ~7UL,
- false))))
- {
- bitmap_set_all(&cols);
- error=
- RowsEventT::binlog_row_logging_function(thd, table,
- table->file->has_transactions(),
- &cols, table->s->fields,
- before_record, after_record);
- if (!use_bitbuf)
- bitmap_free(&cols);
- }
+
+ if (check_table_binlog_row_based(table->in_use, table))
+ {
+ error=
+ RowsEventT::binlog_row_logging_function(table->in_use, table,
+ table->file->has_transactions(),
+ &table->s->all_set,
+ table->s->fields,
+ before_record, after_record);
}
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
}
@@ -3289,6 +3276,28 @@ int handler::ha_external_lock(THD *thd, int lock_type)
DBUG_RETURN(0);
}
+
+/*
+ Check handler usage and reset state of file to after 'open'
+*/
+
+int handler::ha_reset()
+{
+ DBUG_ENTER("ha_reset");
+ /* Check that we have called all proper delallocation functions */
+ DBUG_ASSERT((byte*) table->def_read_set.bitmap +
+ table->s->column_bitmap_size ==
+ (char*) table->def_write_set.bitmap);
+ DBUG_ASSERT(bitmap_is_set_all(&table->s->all_set));
+ DBUG_ASSERT(table->key_read == 0);
+ /* ensure that ha_index_end / ha_rnd_end has been called */
+ DBUG_ASSERT(inited == NONE);
+ /* Free cache used by filesort */
+ free_io_cache(table);
+ DBUG_RETURN(reset());
+}
+
+
int handler::ha_write_row(byte *buf)
{
int error;
@@ -3331,3 +3340,200 @@ int handler::ha_delete_row(const byte *buf)
#endif
return 0;
}
+
+
+
+/*
+ use_hidden_primary_key() is called in case of an update/delete when
+ (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
+ but we don't have a primary key
+*/
+
+void handler::use_hidden_primary_key()
+{
+ /* fallback to use all columns in the table to identify row */
+ table->use_all_columns();
+}
+
+
+/*
+ Dummy function which accept information about log files which is not need
+ by handlers
+*/
+
+void signal_log_not_needed(struct handlerton, char *log_file)
+{
+ DBUG_ENTER("signal_log_not_needed");
+ DBUG_PRINT("enter", ("logfile '%s'", log_file));
+ DBUG_VOID_RETURN;
+}
+
+
+#ifdef TRANS_LOG_MGM_EXAMPLE_CODE
+/*
+ Example of transaction log management functions based on assumption that logs
+ placed into a directory
+*/
+#include <my_dir.h>
+#include <my_sys.h>
+int example_of_iterator_using_for_logs_cleanup(handlerton *hton)
+{
+ void *buffer;
+ int res= 1;
+ struct handler_iterator iterator;
+ struct handler_log_file_data data;
+
+ if (!hton->create_iterator)
+ return 1; /* iterator creator is not supported */
+
+ if ((*hton->create_iterator)(HA_TRANSACTLOG_ITERATOR, &iterator) !=
+ HA_ITERATOR_OK)
+ {
+ /* error during creation of log iterator or iterator is not supported */
+ return 1;
+ }
+ while((*iterator.next)(&iterator, (void*)&data) == 0)
+ {
+ printf("%s\n", data.filename.str);
+ if (data.status == HA_LOG_STATUS_FREE &&
+ my_delete(data.filename.str, MYF(MY_WME)))
+ goto err;
+ }
+ res= 0;
+err:
+ (*iterator.destroy)(&iterator);
+ return res;
+}
+
+
+/*
+ Here we should get info from handler where it save logs but here is
+ just example, so we use constant.
+ IMHO FN_ROOTDIR ("/") is safe enough for example, because nobody has
+ rights on it except root and it consist of directories only at lest for
+ *nix (sorry, can't find windows-safe solution here, but it is only example).
+*/
+#define fl_dir FN_ROOTDIR
+
+
+/*
+ Dummy function to return log status should be replaced by function which
+ really detect the log status and check that the file is a log of this
+ handler.
+*/
+
+enum log_status fl_get_log_status(char *log)
+{
+ MY_STAT stat_buff;
+ if (my_stat(log, &stat_buff, MYF(0)))
+ return HA_LOG_STATUS_INUSE;
+ return HA_LOG_STATUS_NOSUCHLOG;
+}
+
+
+struct fl_buff
+{
+ LEX_STRING *names;
+ enum log_status *statuses;
+ uint32 entries;
+ uint32 current;
+};
+
+
+int fl_log_iterator_next(struct handler_iterator *iterator,
+ void *iterator_object)
+{
+ struct fl_buff *buff= (struct fl_buff *)iterator->buffer;
+ struct handler_log_file_data *data=
+ (struct handler_log_file_data *) iterator_object;
+ if (buff->current >= buff->entries)
+ return 1;
+ data->filename= buff->names[buff->current];
+ data->status= buff->statuses[buff->current];
+ buff->current++;
+ return 0;
+}
+
+
+void fl_log_iterator_destroy(struct handler_iterator *iterator)
+{
+ my_free((gptr)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
+/*
+ returns buffer, to be assigned in handler_iterator struct
+*/
+enum handler_create_iterator_result
+fl_log_iterator_buffer_init(struct handler_iterator *iterator)
+{
+ MY_DIR *dirp;
+ struct fl_buff *buff;
+ char *name_ptr;
+ byte *ptr;
+ FILEINFO *file;
+ uint32 i;
+
+ /* to be able to make my_free without crash in case of error */
+ iterator->buffer= 0;
+
+ if (!(dirp = my_dir(fl_dir, MYF(0))))
+ {
+ return HA_ITERATOR_ERROR;
+ }
+ if ((ptr= (byte*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) +
+ ((ALIGN_SIZE(sizeof(LEX_STRING)) +
+ sizeof(enum log_status) +
+ + FN_REFLEN) *
+ (uint) dirp->number_off_files),
+ MYF(0))) == 0)
+ {
+ return HA_ITERATOR_ERROR;
+ }
+ buff= (struct fl_buff *)ptr;
+ buff->entries= buff->current= 0;
+ ptr= ptr + (ALIGN_SIZE(sizeof(fl_buff)));
+ buff->names= (LEX_STRING*) (ptr);
+ ptr= ptr + ((ALIGN_SIZE(sizeof(LEX_STRING)) *
+ (uint) dirp->number_off_files));
+ buff->statuses= (enum log_status *)(ptr);
+ name_ptr= (char *)(ptr + (sizeof(enum log_status) *
+ (uint) dirp->number_off_files));
+ for (i=0 ; i < (uint) dirp->number_off_files ; i++)
+ {
+ enum log_status st;
+ file= dirp->dir_entry + i;
+ if ((file->name[0] == '.' &&
+ ((file->name[1] == '.' && file->name[2] == '\0') ||
+ file->name[1] == '\0')))
+ continue;
+ if ((st= fl_get_log_status(file->name)) == HA_LOG_STATUS_NOSUCHLOG)
+ continue;
+ name_ptr= strxnmov(buff->names[buff->entries].str= name_ptr,
+ FN_REFLEN, fl_dir, file->name, NullS);
+ buff->names[buff->entries].length= (name_ptr -
+ buff->names[buff->entries].str) - 1;
+ buff->statuses[buff->entries]= st;
+ buff->entries++;
+ }
+
+ iterator->buffer= buff;
+ iterator->next= &fl_log_iterator_next;
+ iterator->destroy= &fl_log_iterator_destroy;
+ return HA_ITERATOR_OK;
+}
+
+
+/* An example of a iterator creator */
+enum handler_create_iterator_result
+fl_create_iterator(enum handler_iterator_type type,
+ struct handler_iterator *iterator)
+{
+ switch(type) {
+ case HA_TRANSACTLOG_ITERATOR:
+ return fl_log_iterator_buffer_init(iterator);
+ default:
+ return HA_ITERATOR_UNSUPPORTED;
+ }
+}
+#endif /*TRANS_LOG_MGM_EXAMPLE_CODE*/
diff --git a/sql/handler.h b/sql/handler.h
index afee6bb9f8d..f459d52fdeb 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -49,14 +49,18 @@
/* Bits in table_flags() to show what database can do */
+#define HA_NO_TRANSACTIONS (1 << 0) /* Doesn't support transactions */
+#define HA_PARTIAL_COLUMN_READ (1 << 1) /* read may not return all columns */
+#define HA_TABLE_SCAN_ON_INDEX (1 << 2) /* No separate data/index file */
/*
- Can switch index during the scan with ::rnd_same() - not used yet.
- see mi_rsame/heap_rsame/myrg_rsame
+ The following should be set if the following is not true when scanning
+ a table with rnd_next()
+ - We will see all rows (including deleted ones)
+ - Row positions are 'table->s->db_record_offset' apart
+ If this flag is not set, filesort will do a postion() call for each matched
+ row to be able to find the row later.
*/
-#define HA_READ_RND_SAME (1 << 0)
-#define HA_TABLE_SCAN_ON_INDEX (1 << 2) /* No separate data/index file */
-#define HA_REC_NOT_IN_SEQ (1 << 3) /* ha_info don't return recnumber;
- It returns a position to ha_r_rnd */
+#define HA_REC_NOT_IN_SEQ (1 << 3)
#define HA_CAN_GEOMETRY (1 << 4)
/*
Reading keys in random order is as fast as reading keys in sort order
@@ -64,28 +68,41 @@
filesort to decide if we should sort key + data or key + pointer-to-row
*/
#define HA_FAST_KEY_READ (1 << 5)
+/*
+ Set the following flag if we on delete should force all key to be read
+ and on update read all keys that changes
+*/
+#define HA_REQUIRES_KEY_COLUMNS_FOR_DELETE (1 << 6)
#define HA_NULL_IN_KEY (1 << 7) /* One can have keys with NULL */
-#define HA_DUPP_POS (1 << 8) /* ha_position() gives dup row */
+#define HA_DUPLICATE_POS (1 << 8) /* ha_position() gives dup row */
#define HA_NO_BLOBS (1 << 9) /* Doesn't support blobs */
#define HA_CAN_INDEX_BLOBS (1 << 10)
#define HA_AUTO_PART_KEY (1 << 11) /* auto-increment in multi-part key */
#define HA_REQUIRE_PRIMARY_KEY (1 << 12) /* .. and can't create a hidden one */
-#define HA_NOT_EXACT_COUNT (1 << 13)
+#define HA_STATS_RECORDS_IS_EXACT (1 << 13) /* stats.records is exact */
/*
INSERT_DELAYED only works with handlers that uses MySQL internal table
level locks
*/
#define HA_CAN_INSERT_DELAYED (1 << 14)
+/*
+ If we get the primary key columns for free when we do an index read
+ It also implies that we have to retrive the primary key when using
+ position() and rnd_pos().
+*/
#define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15)
/*
- If HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS is set, it means that the engine can
- do this: the position of an arbitrary record can be retrieved using
- position() when the table has a primary key, effectively allowing random
- access on the table based on a given record.
+ If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, it means that to position()
+ uses a primary key. Without primary key, we can't call position().
*/
-#define HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS (1 << 16)
+#define HA_PRIMARY_KEY_REQUIRED_FOR_POSITION (1 << 16)
#define HA_CAN_RTREEKEYS (1 << 17)
#define HA_NOT_DELETE_WITH_CACHE (1 << 18)
+/*
+ The following is we need to a primary key to delete (and update) a row.
+ If there is no primary key, all columns needs to be read on update and delete
+*/
+#define HA_PRIMARY_KEY_REQUIRED_FOR_DELETE (1 << 19)
#define HA_NO_PREFIX_CHAR_KEYS (1 << 20)
#define HA_CAN_FULLTEXT (1 << 21)
#define HA_CAN_SQL_HANDLER (1 << 22)
@@ -97,7 +114,8 @@
#define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */
#define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */
#define HA_ANY_INDEX_MAY_BE_UNIQUE (1 << 30)
-#define HA_NO_COPY_ON_ALTER (1 << 31)
+#define HA_NO_COPY_ON_ALTER (LL(1) << 31)
+#define HA_HAS_RECORDS (LL(1) << 32) /* records() gives exact count*/
/* bits in index_flags(index_number) for what you can do with index */
#define HA_READ_NEXT 1 /* TODO really use this flag */
@@ -177,6 +195,7 @@
so: innodb + bdb + ndb + binlog + myisam + myisammrg + archive +
example + csv + heap + blackhole + federated + 0
(yes, the sum is deliberately inaccurate)
+ TODO remove the limit, use dynarrays
*/
#define MAX_HA 15
@@ -240,7 +259,7 @@ enum legacy_db_type
enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED,
- ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT };
+ ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT, ROW_TYPE_PAGES };
enum enum_binlog_func {
BFN_RESET_LOGS= 1,
@@ -460,6 +479,73 @@ typedef bool (stat_print_fn)(THD *thd, const char *type, uint type_len,
const char *file, uint file_len,
const char *status, uint status_len);
enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
+extern st_plugin_int *hton2plugin[MAX_HA];
+
+/* Transaction log maintains type definitions */
+enum log_status
+{
+ HA_LOG_STATUS_FREE= 0, /* log is free and can be deleted */
+ HA_LOG_STATUS_INUSE= 1, /* log can't be deleted because it is in use */
+ HA_LOG_STATUS_NOSUCHLOG= 2 /* no such log (can't be returned by
+ the log iterator status) */
+};
+/*
+ Function for signaling that the log file changed its state from
+ LOG_STATUS_INUSE to LOG_STATUS_FREE
+
+ Now it do nothing, will be implemented as part of new transaction
+ log management for engines.
+ TODO: implement the function.
+*/
+void signal_log_not_needed(struct handlerton, char *log_file);
+/*
+ Data of transaction log iterator.
+*/
+struct handler_log_file_data {
+ LEX_STRING filename;
+ enum log_status status;
+};
+
+
+enum handler_iterator_type
+{
+ /* request of transaction log iterator */
+ HA_TRANSACTLOG_ITERATOR= 1
+};
+enum handler_create_iterator_result
+{
+ HA_ITERATOR_OK, /* iterator created */
+ HA_ITERATOR_UNSUPPORTED, /* such type of iterator is not supported */
+ HA_ITERATOR_ERROR /* error during iterator creation */
+};
+
+/*
+ Iterator structure. Can be used by handler/handlerton for different purposes.
+
+ Iterator should be created in the way to point "before" the first object
+ it iterate, so next() call move it to the first object or return !=0 if
+ there is nothing to iterate through.
+*/
+struct handler_iterator {
+ /*
+ Moves iterator to next record and return 0 or return !=0
+ if there is no records.
+ iterator_object will be filled by this function if next() returns 0.
+ Content of the iterator_object depend on iterator type.
+ */
+ int (*next)(struct handler_iterator *, void *iterator_object);
+ /*
+ Free resources allocated by iterator, after this call iterator
+ is not usable.
+ */
+ void (*destroy)(struct handler_iterator *);
+ /*
+ Pointer to buffer for the iterator to use.
+ Should be allocated by function which created the iterator and
+ destroied by freed by above "destroy" call
+ */
+ void *buffer;
+};
/*
handlerton is a singleton structure - one instance per storage engine -
@@ -475,38 +561,15 @@ enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
struct handlerton
{
/*
- handlerton structure version
- */
- const int interface_version;
-/* last version change: 0x0001 in 5.1.6 */
-#define MYSQL_HANDLERTON_INTERFACE_VERSION 0x0001
-
-
- /*
- storage engine name as it should be printed to a user
- */
- const char *name;
-
- /*
- Historical marker for if the engine is available of not
+ Historical marker for if the engine is available of not
*/
SHOW_COMP_OPTION state;
/*
- A comment used by SHOW to describe an engine.
- */
- const char *comment;
-
- /*
Historical number used for frm file to determine the correct storage engine.
This is going away and new engines will just use "name" for this.
*/
enum legacy_db_type db_type;
- /*
- Method that initizlizes a storage engine
- */
- bool (*init)();
-
/*
each storage engine has it's own memory area (actually a pointer)
in the thd, for storing per-connection information.
@@ -563,7 +626,7 @@ struct handlerton
void *(*create_cursor_read_view)();
void (*set_cursor_read_view)(void *);
void (*close_cursor_read_view)(void *);
- handler *(*create)(TABLE_SHARE *table);
+ handler *(*create)(TABLE_SHARE *table, MEM_ROOT *mem_root);
void (*drop_database)(char* path);
int (*panic)(enum ha_panic_function flag);
int (*start_consistent_snapshot)(THD *thd);
@@ -585,9 +648,24 @@ struct handlerton
const char *query, uint query_length,
const char *db, const char *table_name);
int (*release_temporary_latches)(THD *thd);
-};
-extern const handlerton default_hton;
+ /*
+ Get log status.
+ If log_status is null then the handler do not support transaction
+ log information (i.e. log iterator can't be created).
+ (see example of implementation in handler.cc, TRANS_LOG_MGM_EXAMPLE_CODE)
+
+ */
+ enum log_status (*get_log_status)(char *log);
+
+ /*
+ Iterators creator.
+ Presence of the pointer should be checked before using
+ */
+ enum handler_create_iterator_result
+ (*create_iterator)(enum handler_iterator_type type,
+ struct handler_iterator *fill_this_in);
+};
struct show_table_alias_st {
const char *alias;
@@ -747,11 +825,37 @@ typedef struct st_handler_buffer
typedef struct system_status_var SSV;
+class ha_statistics
+{
+public:
+ ulonglong data_file_length; /* Length off data file */
+ ulonglong max_data_file_length; /* Length off data file */
+ ulonglong index_file_length;
+ ulonglong max_index_file_length;
+ ulonglong delete_length; /* Free bytes */
+ ulonglong auto_increment_value;
+ ha_rows records; /* Estimated records in table */
+ ha_rows deleted; /* Deleted records */
+ ulong mean_rec_length; /* physical reclength */
+ time_t create_time; /* When table was created */
+ time_t check_time;
+ time_t update_time;
+ uint block_size; /* index block size */
+
+ ha_statistics():
+ data_file_length(0), max_data_file_length(0),
+ index_file_length(0), delete_length(0), auto_increment_value(0),
+ records(0), deleted(0), mean_rec_length(0), create_time(0),
+ check_time(0), update_time(0), block_size(0)
+ {}
+};
+
/*
The handler class is the interface for dynamically loadable
storage engines. Do not add ifdefs and take care when adding or
changing virtual functions to avoid vtable confusion
*/
+
class handler :public Sql_alloc
{
friend class ha_partition;
@@ -759,6 +863,7 @@ class handler :public Sql_alloc
protected:
struct st_table_share *table_share; /* The table definition */
struct st_table *table; /* The current open table */
+ ulonglong cached_table_flags; /* Set on init() and open() */
virtual int index_init(uint idx, bool sorted) { active_index=idx; return 0; }
virtual int index_end() { active_index=MAX_KEY; return 0; }
@@ -771,28 +876,18 @@ class handler :public Sql_alloc
*/
virtual int rnd_init(bool scan) =0;
virtual int rnd_end() { return 0; }
-
+ virtual ulonglong table_flags(void) const =0;
void ha_statistic_increment(ulong SSV::*offset) const;
-
-private:
- virtual int reset() { return extra(HA_EXTRA_RESET); }
+ ha_rows estimation_rows_to_insert;
+ virtual void start_bulk_insert(ha_rows rows) {}
+ virtual int end_bulk_insert() {return 0; }
public:
const handlerton *ht; /* storage engine of this handler */
byte *ref; /* Pointer to current row */
- byte *dupp_ref; /* Pointer to dupp row */
- ulonglong data_file_length; /* Length off data file */
- ulonglong max_data_file_length; /* Length off data file */
- ulonglong index_file_length;
- ulonglong max_index_file_length;
- ulonglong delete_length; /* Free bytes */
- ulonglong auto_increment_value;
- ha_rows records; /* Records in table */
- ha_rows deleted; /* Deleted records */
- ulong mean_rec_length; /* physical reclength */
- time_t create_time; /* When table was created */
- time_t check_time;
- time_t update_time;
+ byte *dup_ref; /* Pointer to duplicate row */
+
+ ha_statistics stats;
/* The following are for read_multi_range */
bool multi_range_sorted;
@@ -807,27 +902,20 @@ public:
bool eq_range;
uint errkey; /* Last dup key */
- uint sortkey, key_used_on_scan;
+ uint key_used_on_scan;
uint active_index;
/* Length of ref (1-8 or the clustered key length) */
uint ref_length;
- uint block_size; /* index block size */
FT_INFO *ft_handler;
enum {NONE=0, INDEX, RND} inited;
bool auto_increment_column_changed;
bool implicit_emptied; /* Can be !=0 only if HEAP */
const COND *pushed_cond;
- MY_BITMAP *read_set;
- MY_BITMAP *write_set;
handler(const handlerton *ht_arg, TABLE_SHARE *share_arg)
- :table_share(share_arg), ht(ht_arg),
- ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
- delete_length(0), auto_increment_value(0),
- records(0), deleted(0), mean_rec_length(0),
- create_time(0), check_time(0), update_time(0),
- key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
- ref_length(sizeof(my_off_t)), block_size(0),
+ :table_share(share_arg), estimation_rows_to_insert(0), ht(ht_arg),
+ ref(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
+ ref_length(sizeof(my_off_t)),
ft_handler(0), inited(NONE), implicit_emptied(0),
pushed_cond(NULL)
{}
@@ -835,6 +923,11 @@ public:
{
/* TODO: DBUG_ASSERT(inited == NONE); */
}
+ /* This is called after create to allow us to set up cached variables */
+ void init()
+ {
+ cached_table_flags= table_flags();
+ }
/*
Check whether a handler allows to lock the table.
@@ -862,9 +955,9 @@ public:
{
return TRUE;
}
- virtual int ha_initialise();
int ha_open(TABLE *table, const char *name, int mode, int test_if_locked);
bool update_auto_increment();
+ void print_keydup_error(uint key_nr, const char *msg);
virtual void print_error(int error, myf errflag);
virtual bool get_error_message(int error, String *buf);
uint get_dup_key(int error);
@@ -874,21 +967,27 @@ public:
table_share= share;
}
virtual double scan_time()
- { return ulonglong2double(data_file_length) / IO_SIZE + 2; }
+ { return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; }
virtual double read_time(uint index, uint ranges, ha_rows rows)
- { return rows2double(ranges+rows); }
+ { return rows2double(ranges+rows); }
virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
- virtual bool has_transactions(){ return 0;}
+ bool has_transactions()
+ { return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0; }
virtual uint extra_rec_buf_length() const { return 0; }
/*
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+ */
+ virtual ha_rows records() { return stats.records; }
+ /*
Return upper bound of current number of records in the table
(max. of how many records one will retrieve when doing a full table scan)
If upper bound is not known, HA_POS_ERROR should be returned as a max
possible upper bound.
*/
virtual ha_rows estimate_rows_upper_bound()
- { return records+EXTRA_RECORDS; }
+ { return stats.records+EXTRA_RECORDS; }
/*
Get the row type from the storage engine. If this method returns
@@ -926,139 +1025,23 @@ public:
inited=NONE;
DBUG_RETURN(rnd_end());
}
- int ha_reset()
- {
- DBUG_ENTER("ha_reset");
- ha_clear_all_set();
- DBUG_RETURN(reset());
- }
+ int ha_reset();
/* this is necessary in many places, e.g. in HANDLER command */
int ha_index_or_rnd_end()
{
return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0;
}
+ longlong ha_table_flags() { return cached_table_flags; }
+
/*
- These are a set of routines used to enable handlers to only read/write
- partial lists of the fields in the table. The bit vector is maintained
- by the server part and is used by the handler at calls to read/write
- data in the table.
- It replaces the use of query id's for this purpose. The benefit is that
- the handler can also set bits in the read/write set if it has special
- needs and it is also easy for other parts of the server to interact
- with the handler (e.g. the replication part for row-level logging).
- The routines are all part of the general handler and are not possible
- to override by a handler. A handler can however set/reset bits by
- calling these routines.
-
- The methods ha_retrieve_all_cols and ha_retrieve_all_pk are made
- virtual to handle InnoDB specifics. If InnoDB doesn't need the
- extra parameters HA_EXTRA_RETRIEVE_ALL_COLS and
- HA_EXTRA_RETRIEVE_PRIMARY_KEY anymore then these methods need not be
- virtual anymore.
+ Signal that the table->read_set and table->write_set table maps changed
+ The handler is allowed to set additional bits in the above map in this
+ call. Normally the handler should ignore all calls until we have done
+ a ha_rnd_init() or ha_index_init(), write_row(), update_row or delete_row()
+ as there may be several calls to this routine.
*/
- virtual int ha_retrieve_all_cols();
- virtual int ha_retrieve_all_pk();
- void ha_set_all_bits_in_read_set()
- {
- DBUG_ENTER("ha_set_all_bits_in_read_set");
- bitmap_set_all(read_set);
- DBUG_VOID_RETURN;
- }
- void ha_set_all_bits_in_write_set()
- {
- DBUG_ENTER("ha_set_all_bits_in_write_set");
- bitmap_set_all(write_set);
- DBUG_VOID_RETURN;
- }
- void ha_set_bit_in_read_set(uint fieldnr)
- {
- DBUG_ENTER("ha_set_bit_in_read_set");
- DBUG_PRINT("info", ("fieldnr = %d", fieldnr));
- bitmap_set_bit(read_set, fieldnr);
- DBUG_VOID_RETURN;
- }
- void ha_clear_bit_in_read_set(uint fieldnr)
- {
- DBUG_ENTER("ha_clear_bit_in_read_set");
- DBUG_PRINT("info", ("fieldnr = %d", fieldnr));
- bitmap_clear_bit(read_set, fieldnr);
- DBUG_VOID_RETURN;
- }
- void ha_set_bit_in_write_set(uint fieldnr)
- {
- DBUG_ENTER("ha_set_bit_in_write_set");
- DBUG_PRINT("info", ("fieldnr = %d", fieldnr));
- bitmap_set_bit(write_set, fieldnr);
- DBUG_VOID_RETURN;
- }
- void ha_clear_bit_in_write_set(uint fieldnr)
- {
- DBUG_ENTER("ha_clear_bit_in_write_set");
- DBUG_PRINT("info", ("fieldnr = %d", fieldnr));
- bitmap_clear_bit(write_set, fieldnr);
- DBUG_VOID_RETURN;
- }
- void ha_set_bit_in_rw_set(uint fieldnr, bool write_op)
- {
- DBUG_ENTER("ha_set_bit_in_rw_set");
- DBUG_PRINT("info", ("Set bit %u in read set", fieldnr));
- bitmap_set_bit(read_set, fieldnr);
- if (!write_op) {
- DBUG_VOID_RETURN;
- }
- else
- {
- DBUG_PRINT("info", ("Set bit %u in read and write set", fieldnr));
- bitmap_set_bit(write_set, fieldnr);
- }
- DBUG_VOID_RETURN;
- }
- bool ha_get_bit_in_read_set(uint fieldnr)
- {
- bool bit_set=bitmap_is_set(read_set,fieldnr);
- DBUG_ENTER("ha_get_bit_in_read_set");
- DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set));
- DBUG_RETURN(bit_set);
- }
- bool ha_get_bit_in_write_set(uint fieldnr)
- {
- bool bit_set=bitmap_is_set(write_set,fieldnr);
- DBUG_ENTER("ha_get_bit_in_write_set");
- DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set));
- DBUG_RETURN(bit_set);
- }
- bool ha_get_all_bit_in_read_set()
- {
- bool all_bits_set= bitmap_is_set_all(read_set);
- DBUG_ENTER("ha_get_all_bit_in_read_set");
- DBUG_PRINT("info", ("all bits set = %u", all_bits_set));
- DBUG_RETURN(all_bits_set);
- }
- bool ha_get_all_bit_in_read_clear()
- {
- bool all_bits_set= bitmap_is_clear_all(read_set);
- DBUG_ENTER("ha_get_all_bit_in_read_clear");
- DBUG_PRINT("info", ("all bits clear = %u", all_bits_set));
- DBUG_RETURN(all_bits_set);
- }
- bool ha_get_all_bit_in_write_set()
- {
- bool all_bits_set= bitmap_is_set_all(write_set);
- DBUG_ENTER("ha_get_all_bit_in_write_set");
- DBUG_PRINT("info", ("all bits set = %u", all_bits_set));
- DBUG_RETURN(all_bits_set);
- }
- bool ha_get_all_bit_in_write_clear()
- {
- bool all_bits_set= bitmap_is_clear_all(write_set);
- DBUG_ENTER("ha_get_all_bit_in_write_clear");
- DBUG_PRINT("info", ("all bits clear = %u", all_bits_set));
- DBUG_RETURN(all_bits_set);
- }
- void ha_set_primary_key_in_read_set();
- int ha_allocate_read_write_set(ulong no_fields);
- void ha_clear_all_set();
+ virtual void column_bitmaps_signal();
uint get_index(void) const { return active_index; }
virtual int open(const char *name, int mode, uint test_if_locked)=0;
virtual int close(void)=0;
@@ -1211,6 +1194,13 @@ public:
{ return 0; }
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
{ return extra(operation); }
+
+ /*
+ Reset state of file to after 'open'
+ This function is called after every statement for all tables used
+ by that statement.
+ */
+ virtual int reset() { return 0; }
/*
In an UPDATE or DELETE, if the row under the cursor was locked by another
transaction, and the engine used an optimistic read of the last
@@ -1241,7 +1231,11 @@ public:
*/
virtual int delete_all_rows()
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
- virtual ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
+ virtual void release_auto_increment() { return; };
virtual void restore_auto_increment();
/*
@@ -1302,8 +1296,16 @@ public:
virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; }
virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; }
virtual int indexes_are_disabled(void) {return 0;}
- virtual void start_bulk_insert(ha_rows rows) {}
- virtual int end_bulk_insert() {return 0; }
+ void ha_start_bulk_insert(ha_rows rows)
+ {
+ estimation_rows_to_insert= rows;
+ start_bulk_insert(rows);
+ }
+ int ha_end_bulk_insert()
+ {
+ estimation_rows_to_insert= 0;
+ return end_bulk_insert();
+ }
virtual int discard_or_import_tablespace(my_bool discard)
{return HA_ERR_WRONG_COMMAND;}
virtual int net_read_dump(NET* net) { return HA_ERR_WRONG_COMMAND; }
@@ -1340,7 +1342,6 @@ public:
/* The following can be called without an open handler */
virtual const char *table_type() const =0;
virtual const char **bas_ext() const =0;
- virtual ulong table_flags(void) const =0;
virtual int get_default_no_partitions(ulonglong max_rows) { return 1;}
virtual void set_auto_partitions(partition_info *part_info) { return; }
@@ -1449,7 +1450,6 @@ public:
false otherwise
*/
virtual bool primary_key_is_clustered() { return FALSE; }
-
virtual int cmp_ref(const byte *ref1, const byte *ref2)
{
return memcmp(ref1, ref2, ref_length);
@@ -1465,10 +1465,12 @@ public:
cond_push()
cond Condition to be pushed. The condition tree must not be
modified by the by the caller.
+
RETURN
The 'remainder' condition that caller must use to filter out records.
NULL means the handler will not return rows that do not match the
passed condition.
+
NOTES
The pushed conditions form a stack (from which one can remove the
last pushed condition using cond_pop).
@@ -1476,7 +1478,7 @@ public:
AND ... AND pushed_condN)
or less restrictive condition, depending on handler's capabilities.
- handler->extra(HA_EXTRA_RESET) call empties the condition stack.
+ handler->ha_reset() call empties the condition stack.
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
condition stack.
*/
@@ -1492,18 +1494,7 @@ public:
uint table_changes)
{ return COMPATIBLE_DATA_NO; }
-private:
- /*
- Row-level primitives for storage engines. These should be
- overridden by the storage engine class. To call these methods, use
- the corresponding 'ha_*' method above.
- */
- virtual int external_lock(THD *thd __attribute__((unused)),
- int lock_type __attribute__((unused)))
- {
- return 0;
- }
-
+ /* These are only called from sql_select for internal temporary tables */
virtual int write_row(byte *buf __attribute__((unused)))
{
return HA_ERR_WRONG_COMMAND;
@@ -1519,6 +1510,24 @@ private:
{
return HA_ERR_WRONG_COMMAND;
}
+ /*
+ use_hidden_primary_key() is called in case of an update/delete when
+ (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
+ but we don't have a primary key
+ */
+ virtual void use_hidden_primary_key();
+
+private:
+ /*
+ Row-level primitives for storage engines. These should be
+ overridden by the storage engine class. To call these methods, use
+ the corresponding 'ha_*' method above.
+ */
+ virtual int external_lock(THD *thd __attribute__((unused)),
+ int lock_type __attribute__((unused)))
+ {
+ return 0;
+ }
};
/* Some extern variables used with handlers */
@@ -1552,7 +1561,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" : db_type->name;
+ return db_type == NULL ? "UNKNOWN" : hton2plugin[db_type->slot]->name.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 32890ec3596..5fa3ad61c15 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -304,6 +304,7 @@ Item::Item():
marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
decimals= 0; max_length= 0;
+ with_subselect= 0;
/* Put item in free list so that we can free all items at end */
THD *thd= current_thd;
@@ -550,6 +551,23 @@ bool Item_field::find_item_in_field_list_processor(byte *arg)
}
+/*
+ Mark field in read_map
+
+ NOTES
+ This is used by filesort to register used fields in a a temporary
+ column read set or to register used fields in a view
+*/
+
+bool Item_field::register_field_in_read_map(byte *arg)
+{
+ TABLE *table= (TABLE *) arg;
+ if (field->table == table || !table)
+ bitmap_set_bit(field->table->read_set, field->field_index);
+ return 0;
+}
+
+
bool Item::check_cols(uint c)
{
if (c != 1)
@@ -789,14 +807,25 @@ CHARSET_INFO *Item::default_charset()
}
+/*
+ Save value in field, but don't give any warnings
+
+ NOTES
+ This is used to temporary store and retrieve a value in a column,
+ for example in opt_range to adjust the key value to fit the column.
+*/
+
int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
{
int res;
- THD *thd= field->table->in_use;
+ TABLE *table= field->table;
+ THD *thd= table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
thd->count_cuted_fields= tmp;
+ dbug_tmp_restore_column_map(table->write_set, old_map);
return res;
}
@@ -2365,7 +2394,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
- value.cs_info.character_set_of_placeholder= fromcs;
+ value.cs_info.character_set_of_placeholder=
+ value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
@@ -3568,7 +3598,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&not_used);
- if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM)
+ if (res != (Item **)not_found_item &&
+ (*res)->type() == Item::FIELD_ITEM)
{
set_field((*((Item_field**)res))->field);
return 0;
@@ -3587,7 +3618,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if it is not expression from merged VIEW we will set this field.
We can leave expression substituted from view for next PS/SP rexecution
- (i.e. do not register this substitution for reverting on cleupup()
+ (i.e. do not register this substitution for reverting on cleanup()
(register_item_tree_changing())), because this subtree will be
fix_field'ed during setup_tables()->setup_underlying() (i.e. before
all other expressions of query, and references on tables which do
@@ -3599,13 +3630,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
return FALSE;
if (!outer_fixed && cached_table && cached_table->select_lex &&
- context->select_lex &&
- cached_table->select_lex != context->select_lex)
+ context->select_lex &&
+ cached_table->select_lex != context->select_lex)
{
int ret;
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
goto error;
- else if (!ret)
+ if (!ret)
return FALSE;
}
@@ -3616,17 +3647,28 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
thd->lex->current_select->nest_level);
}
- else if (thd->set_query_id)
+ else if (thd->mark_used_columns != MARK_COLUMNS_NONE)
{
TABLE *table= field->table;
- table->file->ha_set_bit_in_rw_set(field->fieldnr,
- (bool)(thd->set_query_id-1));
- if (field->query_id != thd->query_id)
+ MY_BITMAP *current_bitmap, *other_bitmap;
+ if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ {
+ current_bitmap= table->read_set;
+ other_bitmap= table->write_set;
+ }
+ else
{
- /* We only come here in unions */
- field->query_id=thd->query_id;
- table->used_fields++;
- table->used_keys.intersect(field->part_of_key);
+ current_bitmap= table->write_set;
+ other_bitmap= table->read_set;
+ }
+ if (!bitmap_fast_test_and_set(current_bitmap, field->field_index))
+ {
+ if (!bitmap_is_set(other_bitmap, field->field_index))
+ {
+ /* First usage of column */
+ table->used_fields++; // Used to optimize loops
+ table->used_keys.intersect(field->part_of_key);
+ }
}
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4881,7 +4923,16 @@ void Item_ref::cleanup()
void Item_ref::print(String *str)
{
if (ref)
- (*ref)->print(str);
+ {
+ if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
+ name && alias_name_used)
+ {
+ THD *thd= current_thd;
+ append_identifier(thd, str, name, (uint) strlen(name));
+ }
+ else
+ (*ref)->print(str);
+ }
else
Item_ident::print(str);
}
@@ -5388,17 +5439,17 @@ void Item_insert_value::print(String *str)
void Item_trigger_field::setup_field(THD *thd, TABLE *table,
GRANT_INFO *table_grant_info)
{
- bool save_set_query_id= thd->set_query_id;
+ enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
/* TODO: Think more about consequences of this step. */
- thd->set_query_id= 0;
+ thd->mark_used_columns= MARK_COLUMNS_NONE;
/*
Try to find field by its name and if it will be found
set field_idx properly.
*/
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
0, &field_idx);
- thd->set_query_id= save_set_query_id;
+ thd->mark_used_columns= save_mark_used_columns;
triggers= table->triggers;
table_grants= table_grant_info;
}
@@ -5413,7 +5464,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const
}
-void Item_trigger_field::set_required_privilege(const bool rw)
+void Item_trigger_field::set_required_privilege(bool rw)
{
/*
Require SELECT and UPDATE privilege if this field will be read and
diff --git a/sql/item.h b/sql/item.h
index 8d740c51cad..54cab34eb78 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -417,6 +417,8 @@ public:
required, otherwise we only reading it and SELECT
privilege might be required.
*/
+ Settable_routine_parameter() {}
+ virtual ~Settable_routine_parameter() {}
virtual void set_required_privilege(bool rw) {};
/*
@@ -490,6 +492,9 @@ public:
my_bool is_autogenerated_name; /* indicate was name of this Item
autogenerated or set by user */
DTCollation collation;
+ my_bool with_subselect; /* If this item is a subselect or some
+ of its arguments is or contains a
+ subselect */
// alloc & destruct is done as start of select using sql_alloc
Item();
@@ -757,7 +762,7 @@ public:
static CHARSET_INFO *default_charset();
virtual CHARSET_INFO *compare_collation() { return NULL; }
- virtual bool walk(Item_processor processor, byte *arg)
+ virtual bool walk(Item_processor processor, bool walk_subquery, byte *arg)
{
return (this->*processor)(arg);
}
@@ -779,7 +784,30 @@ public:
virtual bool collect_item_field_processor(byte * arg) { return 0; }
virtual bool find_item_in_field_list_processor(byte *arg) { return 0; }
virtual bool change_context_processor(byte *context) { return 0; }
- virtual bool reset_query_id_processor(byte *query_id) { return 0; }
+ virtual bool register_field_in_read_map(byte *arg) { return 0; }
+ /*
+ Check if a partition function is allowed
+ SYNOPSIS
+ check_partition_func_processor()
+ bool_arg Return argument
+ RETURN VALUE
+ 0
+ DESCRIPTION
+ check_partition_func_processor is used to check if a partition function
+ uses an allowed function. The default is that an item is not allowed
+ in a partition function. However all mathematical functions, string
+ manipulation functions, date functions are allowed. Allowed functions
+ can never depend on server version, they cannot depend on anything
+ related to the environment. They can also only depend on a set of
+ fields in the table itself. They cannot depend on other tables and
+ cannot contain any queries and cannot contain udf's or similar.
+ If a new Item class is defined and it inherits from a class that is
+ allowed in a partition function then it is very important to consider
+ whether this should be inherited to the new class. If not the function
+ below should be defined in the new Item class.
+ */
+ virtual bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual Item *set_no_const_sub(byte *arg) { return this; }
@@ -1070,6 +1098,7 @@ public:
Item::maybe_null= TRUE;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0; }
bool fix_fields(THD *, Item **);
enum Type type() const;
@@ -1116,6 +1145,7 @@ public:
Item_num() {} /* Remove gcc warning */
virtual Item_num *neg()= 0;
Item *safe_charset_converter(CHARSET_INFO *tocs);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
#define NO_CACHED_FIELD_INDEX ((uint)(-1))
@@ -1250,13 +1280,8 @@ public:
Item *get_tmp_table_item(THD *thd);
bool collect_item_field_processor(byte * arg);
bool find_item_in_field_list_processor(byte *arg);
- bool reset_query_id_processor(byte *arg)
- {
- field->query_id= *((query_id_t *) arg);
- if (result_field)
- result_field->query_id= field->query_id;
- return 0;
- }
+ bool register_field_in_read_map(byte *arg);
+ bool check_partition_func_processor(byte *bool_arg) { return 0; }
void cleanup();
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg);
@@ -1300,6 +1325,7 @@ public:
bool is_null() { return 1; }
void print(String *str) { str->append(STRING_WITH_LEN("NULL")); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_null_result :public Item_null
@@ -1312,6 +1338,8 @@ public:
{
save_in_field(result_field, no_conversions);
}
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
/* Item represents one placeholder ('?') of prepared statement */
@@ -1602,6 +1630,8 @@ public:
{}
void print(String *str) { str->append(func_name); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
@@ -1679,6 +1709,7 @@ public:
void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -1693,6 +1724,8 @@ public:
{}
Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
@@ -1705,6 +1738,8 @@ public:
&my_charset_bin)
{ max_length=19;}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
class Item_empty_string :public Item_string
@@ -1727,6 +1762,8 @@ public:
unsigned_flag=1;
}
enum_field_types field_type() const { return int_field_type; }
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
@@ -1750,6 +1787,7 @@ public:
void cleanup() {}
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -1863,8 +1901,8 @@ public:
{
return ref ? (*ref)->real_item() : this;
}
- bool walk(Item_processor processor, byte *arg)
- { return (*ref)->walk(processor, arg); }
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg)
+ { return (*ref)->walk(processor, walk_subquery, arg); }
void print(String *str);
void cleanup();
Item_field *filed_for_view_update()
@@ -1972,6 +2010,8 @@ public:
}
Item *new_item();
virtual Item *real_item() { return ref; }
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
#ifdef MYSQL_SERVER
@@ -2113,9 +2153,9 @@ public:
int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
- bool walk(Item_processor processor, byte *args)
+ bool walk(Item_processor processor, bool walk_subquery, byte *args)
{
- return arg->walk(processor, args) ||
+ return arg->walk(processor, walk_subquery, args) ||
(this->*processor)(args);
}
@@ -2160,9 +2200,9 @@ public:
}
table_map used_tables() const { return (table_map)0L; }
- bool walk(Item_processor processor, byte *args)
+ bool walk(Item_processor processor, bool walk_subquery, byte *args)
{
- return arg->walk(processor, args) ||
+ return arg->walk(processor, walk_subquery, args) ||
(this->*processor)(args);
}
};
@@ -2233,7 +2273,7 @@ public:
void cleanup();
private:
- void set_required_privilege(const bool rw);
+ void set_required_privilege(bool rw);
bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
public:
@@ -2286,6 +2326,7 @@ public:
max_length= item->max_length;
decimals= item->decimals;
collation.set(item->collation);
+ unsigned_flag= item->unsigned_flag;
return 0;
};
virtual void store(Item *)= 0;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index eb26f7ff960..3a1f4b50458 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -204,10 +204,28 @@ longlong Item_func_nop_all::val_int()
/*
- Convert a constant expression or string to an integer.
- This is done when comparing DATE's of different formats and
- also when comparing bigint to strings (in which case the string
- is converted once to a bigint).
+ Convert a constant item to an int and replace the original item
+
+ SYNOPSIS
+ convert_constant_item()
+ thd thread handle
+ field item will be converted using the type of this field
+ item [in/out] reference to the item to convert
+
+ DESCRIPTION
+ The function converts a constant expression or string to an integer.
+ On successful conversion the original item is substituted for the
+ result of the item evaluation.
+ This is done when comparing DATE/TIME of different formats and
+ also when comparing bigint to strings (in which case strings
+ are converted to bigints).
+
+ NOTES
+ This function is called only at prepare stage.
+ As all derived tables are filled only after all derived tables
+ are prepared we do not evaluate items with subselects here because
+ they can contain derived tables and thus we may attempt to use a
+ table that has not been populated yet.
RESULT VALUES
0 Can't convert item
@@ -216,23 +234,31 @@ longlong Item_func_nop_all::val_int()
static bool convert_constant_item(THD *thd, Field *field, Item **item)
{
- if ((*item)->const_item())
+ int result= 0;
+ if (!(*item)->with_subselect && (*item)->const_item())
{
/* For comparison purposes allow invalid dates like 2000-01-32 */
- ulong orig_sql_mode= field->table->in_use->variables.sql_mode;
- field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
+ TABLE *table= field->table;
+ ulong orig_sql_mode= table->in_use->variables.sql_mode;
+ my_bitmap_map *old_write_map=
+ dbug_tmp_use_all_columns(table, table->write_set);
+ my_bitmap_map *old_read_map=
+ dbug_tmp_use_all_columns(table, table->read_set);
+
+ table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
- Item *tmp=new Item_int_with_ref(field->val_int(), *item,
- test(field->flags & UNSIGNED_FLAG));
- field->table->in_use->variables.sql_mode= orig_sql_mode;
+ Item *tmp= new Item_int_with_ref(field->val_int(), *item,
+ test(field->flags & UNSIGNED_FLAG));
if (tmp)
thd->change_item_tree(item, tmp);
- return 1; // Item was replaced
+ result= 1; // Item was replaced
}
- field->table->in_use->variables.sql_mode= orig_sql_mode;
+ table->in_use->variables.sql_mode= orig_sql_mode;
+ dbug_tmp_restore_column_map(table->write_set, old_write_map);
+ dbug_tmp_restore_column_map(table->read_set, old_read_map);
}
- return 0;
+ return result;
}
@@ -2570,7 +2596,9 @@ Item_cond::fix_fields(THD *thd, Item **ref)
(item= *li.ref())->check_cols(1))
return TRUE; /* purecov: inspected */
used_tables_cache|= item->used_tables();
- if (!item->const_item())
+ if (item->const_item())
+ and_tables_cache= (table_map) 0;
+ else
{
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
@@ -2578,6 +2606,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
const_item_cache= FALSE;
}
with_sum_func= with_sum_func || item->with_sum_func;
+ with_subselect|= item->with_subselect;
if (item->maybe_null)
maybe_null=1;
}
@@ -2587,14 +2616,14 @@ Item_cond::fix_fields(THD *thd, Item **ref)
return FALSE;
}
-bool Item_cond::walk(Item_processor processor, byte *arg)
+bool Item_cond::walk(Item_processor processor, bool walk_subquery, byte *arg)
{
List_iterator_fast<Item> li(list);
Item *item;
while ((item= li++))
- if (item->walk(processor, arg))
+ if (item->walk(processor, walk_subquery, arg))
return 1;
- return Item_func::walk(processor, arg);
+ return Item_func::walk(processor, walk_subquery, arg);
}
@@ -3840,14 +3869,16 @@ void Item_equal::fix_length_and_dec()
eval_item->cmp_charset= cmp_collation.collation;
}
-bool Item_equal::walk(Item_processor processor, byte *arg)
+bool Item_equal::walk(Item_processor processor, bool walk_subquery, byte *arg)
{
List_iterator_fast<Item_field> it(fields);
Item *item;
while ((item= it++))
- if (item->walk(processor, arg))
+ {
+ if (item->walk(processor, walk_subquery, arg))
return 1;
- return Item_func::walk(processor, arg);
+ }
+ return Item_func::walk(processor, walk_subquery, arg);
}
Item *Item_equal::transform(Item_transformer transformer, byte *arg)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1cfdcef02d0..8bd1b53e226 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -239,6 +239,7 @@ public:
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_not :public Item_bool_func
@@ -249,6 +250,7 @@ public:
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_maxmin_subselect;
@@ -463,6 +465,7 @@ public:
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -474,6 +477,7 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "strcmp"; }
void print(String *str) { Item_func::print(str); }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -536,6 +540,7 @@ public:
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
uint decimal_precision() const;
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -576,6 +581,7 @@ public:
void print(String *str) { Item_func::print(str); }
table_map not_null_tables() const { return 0; }
bool is_null();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -618,6 +624,7 @@ public:
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -968,6 +975,7 @@ public:
bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
/* Functions used by where clause */
@@ -1009,6 +1017,7 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
Item *neg_transformer(THD *thd);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
/* Functions used by HAVING for rewriting IN subquery */
@@ -1030,6 +1039,8 @@ public:
*/
table_map used_tables() const
{ return used_tables_cache | RAND_TABLE_BIT; }
+ bool check_partition_func_processor(byte *bool_arg)
+ { *(bool *)bool_arg= FALSE; return 0; }
};
@@ -1052,6 +1063,7 @@ public:
void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
void top_level_item() { abort_on_null=1; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -1090,6 +1102,7 @@ public:
const char *func_name() const { return "like"; }
bool fix_fields(THD *thd, Item **ref);
void cleanup();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
#ifdef USE_REGEX
@@ -1112,6 +1125,7 @@ public:
const char *func_name() const { return "regexp"; }
void print(String *str) { print_op(str); }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
#else
@@ -1164,10 +1178,11 @@ public:
COND **conds);
void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item);
- bool walk(Item_processor processor, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -1277,7 +1292,7 @@ public:
void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
void update_used_tables();
- bool walk(Item_processor processor, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
void print(String *str);
CHARSET_INFO *compare_collation()
diff --git a/sql/item_func.cc b/sql/item_func.cc
index fc4cb4ba988..3b633295f20 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -184,6 +184,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
used_tables_cache|= item->used_tables();
not_null_tables_cache|= item->not_null_tables();
const_item_cache&= item->const_item();
+ with_subselect|= item->with_subselect;
}
}
fix_length_and_dec();
@@ -193,14 +194,16 @@ Item_func::fix_fields(THD *thd, Item **ref)
return FALSE;
}
-bool Item_func::walk (Item_processor processor, byte *argument)
+
+bool Item_func::walk(Item_processor processor, bool walk_subquery,
+ byte *argument)
{
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
{
- if ((*arg)->walk(processor, argument))
+ if ((*arg)->walk(processor, walk_subquery, argument))
return 1;
}
}
@@ -4396,7 +4399,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
return TRUE;
}
table=((Item_field *)item)->field->table;
- if (!(table->file->table_flags() & HA_CAN_FULLTEXT))
+ if (!(table->file->ha_table_flags() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
return 1;
diff --git a/sql/item_func.h b/sql/item_func.h
index 1d8a1bd5e22..0aedae73bdc 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -182,7 +182,7 @@ public:
{
return agg_item_charsets(c, func_name(), items, nitems, flags);
}
- bool walk(Item_processor processor, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
@@ -247,6 +247,7 @@ public:
void fix_num_length_and_dec();
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -259,6 +260,7 @@ class Item_num_op :public Item_func_numhybrid
void print(String *str) { print_op(str); }
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -309,7 +311,7 @@ public:
{ max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str);
uint decimal_precision() const { return args[0]->decimal_precision(); }
-
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -343,6 +345,7 @@ public:
void fix_length_and_dec() {};
const char *func_name() const { return "decimal_typecast"; }
void print(String *);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -411,6 +414,7 @@ public:
const char *func_name() const { return "DIV"; }
void fix_length_and_dec();
void print(String *str) { print_op(str); }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -483,6 +487,7 @@ public:
Item_func_exp(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "exp"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -492,6 +497,7 @@ public:
Item_func_ln(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "ln"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -502,6 +508,7 @@ public:
Item_func_log(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "log"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -511,6 +518,7 @@ public:
Item_func_log2(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log2"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -520,6 +528,7 @@ public:
Item_func_log10(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log10"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -529,6 +538,7 @@ public:
Item_func_sqrt(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sqrt"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -538,6 +548,7 @@ public:
Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "pow"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -547,6 +558,7 @@ public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "acos"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_asin :public Item_dec_func
@@ -555,6 +567,7 @@ public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "asin"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_atan :public Item_dec_func
@@ -564,6 +577,7 @@ public:
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "atan"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_cos :public Item_dec_func
@@ -572,6 +586,7 @@ public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "cos"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_sin :public Item_dec_func
@@ -580,6 +595,7 @@ public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sin"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_tan :public Item_dec_func
@@ -588,6 +604,7 @@ public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "tan"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_integer :public Item_int_func
@@ -664,6 +681,7 @@ public:
Item_func_sign(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "sign"; }
longlong val_int();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -678,6 +696,7 @@ public:
const char *func_name() const { return name; }
void fix_length_and_dec()
{ decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -695,6 +714,7 @@ public:
my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_min :public Item_func_min_max
@@ -720,6 +740,7 @@ public:
longlong val_int();
const char *func_name() const { return "length"; }
void fix_length_and_dec() { max_length=10; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_bit_length :public Item_func_length
@@ -739,6 +760,7 @@ public:
longlong val_int();
const char *func_name() const { return "char_length"; }
void fix_length_and_dec() { max_length=10; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_coercibility :public Item_int_func
@@ -749,6 +771,7 @@ public:
const char *func_name() const { return "coercibility"; }
void fix_length_and_dec() { max_length=10; maybe_null= 0; }
table_map not_null_tables() const { return 0; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_locate :public Item_int_func
@@ -762,6 +785,7 @@ public:
longlong val_int();
void fix_length_and_dec();
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -786,6 +810,7 @@ public:
longlong val_int();
const char *func_name() const { return "ascii"; }
void fix_length_and_dec() { max_length=3; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_ord :public Item_int_func
@@ -795,6 +820,7 @@ public:
Item_func_ord(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "ord"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_find_in_set :public Item_int_func
@@ -808,6 +834,7 @@ public:
longlong val_int();
const char *func_name() const { return "find_in_set"; }
void fix_length_and_dec();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */
@@ -819,6 +846,7 @@ public:
Item_func_bit(Item *a) :Item_int_func(a) {}
void fix_length_and_dec() { unsigned_flag= 1; }
void print(String *str) { print_op(str); }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_bit_or :public Item_func_bit
@@ -844,6 +872,7 @@ public:
longlong val_int();
const char *func_name() const { return "bit_count"; }
void fix_length_and_dec() { max_length=2; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_shift_left :public Item_func_bit
@@ -1280,6 +1309,7 @@ public:
longlong val_int();
const char *func_name() const { return "inet_aton"; }
void fix_length_and_dec() { decimals = 0; max_length = 21; maybe_null=1;}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index f5c8d511025..c7b678323a8 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -142,16 +142,18 @@ void Item_row::print(String *str)
str->append(')');
}
-bool Item_row::walk(Item_processor processor, byte *arg)
+
+bool Item_row::walk(Item_processor processor, bool walk_subquery, byte *arg)
{
for (uint i= 0; i < arg_count; i++)
{
- if (items[i]->walk(processor, arg))
+ if (items[i]->walk(processor, walk_subquery, arg))
return 1;
}
return (this->*processor)(arg);
}
+
Item *Item_row::transform(Item_transformer transformer, byte *arg)
{
for (uint i= 0; i < arg_count; i++)
diff --git a/sql/item_row.h b/sql/item_row.h
index d6dd4371372..39913086e8d 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -68,7 +68,7 @@ public:
void update_used_tables();
void print(String *str);
- bool walk(Item_processor processor, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
uint cols() { return arg_count; }
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 7d7b62df0dc..35d8ac1873b 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -47,6 +47,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "md5"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -57,6 +58,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "sha"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_aes_encrypt :public Item_str_func
@@ -87,6 +89,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "concat"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_concat_ws :public Item_str_func
@@ -107,6 +110,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "reverse"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -144,6 +148,7 @@ protected:
public:
Item_str_conv(Item *item) :Item_str_func(item) {}
String *val_str(String *);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -207,6 +212,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "substr"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -218,6 +224,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "substring_index"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -232,6 +239,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "trim"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -411,6 +419,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "soundex"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -446,10 +455,10 @@ public:
void update_used_tables();
const char *func_name() const { return "make_set"; }
- bool walk(Item_processor processor, byte *arg)
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg)
{
- return item->walk(processor, arg) ||
- Item_str_func::walk(processor, arg);
+ return item->walk(processor, walk_subquery, arg) ||
+ Item_str_func::walk(processor, walk_subquery, arg);
}
Item *transform(Item_transformer transformer, byte *arg)
{
@@ -518,6 +527,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "rpad"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -530,6 +540,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "lpad"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -542,8 +553,9 @@ public:
void fix_length_and_dec()
{
collation.set(default_charset());
- decimals=0; max_length=64;
+ max_length= 64;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -560,6 +572,7 @@ public:
decimals=0;
max_length=args[0]->max_length*2*collation.collation->mbmaxlen;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_unhex :public Item_str_func
@@ -575,6 +588,7 @@ public:
decimals=0;
max_length=(1+args[0]->max_length)/2;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -598,6 +612,7 @@ public:
}
void print(String *str);
const char *func_name() const { return "cast_as_binary"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -637,6 +652,7 @@ public:
String* val_str(String* str);
const char *func_name() const { return "inet_ntoa"; }
void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_quote :public Item_str_func
@@ -651,6 +667,7 @@ public:
collation.set(args[0]->collation);
max_length= args[0]->max_length * 2 + 2;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_conv_charset :public Item_str_func
@@ -693,6 +710,7 @@ public:
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_set_collation :public Item_str_func
@@ -725,6 +743,7 @@ public:
maybe_null= 0;
};
table_map not_null_tables() const { return 0; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_collation :public Item_str_func
@@ -740,6 +759,7 @@ public:
maybe_null= 0;
};
table_map not_null_tables() const { return 0; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_crc32 :public Item_int_func
@@ -750,6 +770,7 @@ public:
const char *func_name() const { return "crc32"; }
void fix_length_and_dec() { max_length=10; }
longlong val_int();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_uncompressed_length : public Item_int_func
@@ -760,6 +781,7 @@ public:
const char *func_name() const{return "uncompressed_length";}
void fix_length_and_dec() { max_length=10; }
longlong val_int();
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
#ifdef HAVE_COMPRESS
@@ -776,6 +798,7 @@ public:
void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
const char *func_name() const{return "compress";}
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_uncompress: public Item_str_func
@@ -786,6 +809,7 @@ public:
void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;}
const char *func_name() const{return "uncompress";}
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
#define UUID_LENGTH (8+1+4+1+4+1+4+1+12)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 6472c1b9613..a08ac5d5f6a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -39,6 +39,7 @@ Item_subselect::Item_subselect():
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0), changed(0)
{
+ with_subselect= 1;
reset();
/*
item value is NULL if select_subselect not changed this value
@@ -194,6 +195,46 @@ err:
return res;
}
+
+bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
+ byte *argument)
+{
+
+ if (walk_subquery)
+ {
+ for (SELECT_LEX *lex= unit->first_select(); lex; lex= lex->next_select())
+ {
+ List_iterator<Item> li(lex->item_list);
+ Item *item;
+ ORDER *order;
+
+ if (lex->where && (lex->where)->walk(processor, walk_subquery, argument))
+ return 1;
+ if (lex->having && (lex->having)->walk(processor, walk_subquery,
+ argument))
+ return 1;
+
+ while ((item=li++))
+ {
+ if (item->walk(processor, walk_subquery, argument))
+ return 1;
+ }
+ for (order= (ORDER*) lex->order_list.first ; order; order= order->next)
+ {
+ if ((*order->item)->walk(processor, walk_subquery, argument))
+ return 1;
+ }
+ for (order= (ORDER*) lex->group_list.first ; order; order= order->next)
+ {
+ if ((*order->item)->walk(processor, walk_subquery, argument))
+ return 1;
+ }
+ }
+ }
+ return (this->*processor)(argument);
+}
+
+
bool Item_subselect::exec()
{
int res;
@@ -373,7 +414,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
as far as we moved content to upper level, field which depend of
'upper' select is not really dependent => we remove this dependence
*/
- substitution->walk(&Item::remove_dependence_processor,
+ substitution->walk(&Item::remove_dependence_processor, 0,
(byte *) select_lex->outer_select());
/* SELECT without FROM clause can't have WHERE or HAVING clause */
DBUG_ASSERT(join->conds == 0 && join->having == 0);
@@ -406,6 +447,7 @@ void Item_singlerow_subselect::fix_length_and_dec()
engine->fix_length_and_dec(row);
value= *row;
}
+ unsigned_flag= value->unsigned_flag;
/*
If there are not tables in subquery then ability to have NULL value
depends on SELECT list (if single row subquery have tables then it
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 293408dc09e..85bd7a1139d 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -121,6 +121,7 @@ public:
*/
virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
+ bool walk(Item_processor processor, bool walk_subquery, byte *arg);
friend class select_subselect;
friend class Item_in_optimizer;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 50c22495463..1285e842769 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -353,14 +353,15 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
}
-bool Item_sum::walk (Item_processor processor, byte *argument)
+bool Item_sum::walk (Item_processor processor, bool walk_subquery,
+ byte *argument)
{
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
{
- if ((*arg)->walk(processor, argument))
+ if ((*arg)->walk(processor, walk_subquery, argument))
return 1;
}
}
@@ -734,7 +735,7 @@ static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
static int item_sum_distinct_walk(void *element, element_count num_of_dups,
void *item)
{
- return ((Item_sum_distinct*) (item))->unique_walk_function(element);
+ return ((Item_sum_distinct*) (item))->unique_walk_function(element);
}
C_MODE_END
@@ -2688,7 +2689,7 @@ longlong Item_sum_count_distinct::val_int()
return (longlong) count;
}
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- return table->file->records;
+ return table->file->stats.records;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index f4ff257aa4e..a0cd08dcb11 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -312,7 +312,7 @@ public:
Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
- bool walk (Item_processor processor, byte *argument);
+ bool walk(Item_processor processor, bool walk_subquery, byte *argument);
bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref);
bool register_sum_func(THD *thd, Item **ref);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 9d98e446c84..a2c7af79ef3 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2010,39 +2010,11 @@ longlong Item_date_add_interval::val_int()
bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
{
- INTERVAL interval, other_interval;
- String val= value; // Because of const
-
- if (this == item)
- return TRUE;
-
- if ((item->type() != FUNC_ITEM) ||
- (arg_count != ((Item_func*) item)->arg_count) ||
- (func_name() != ((Item_func*) item)->func_name()))
- return FALSE;
-
Item_date_add_interval *other= (Item_date_add_interval*) item;
-
- if ((int_type != other->int_type) ||
- (!args[0]->eq(other->args[0], binary_cmp)))
- return FALSE;
-
- if (!args[1]->const_item() || !other->args[1]->const_item())
- return (args[1]->eq(other->args[1], binary_cmp));
-
- if (get_interval_value(args[1], int_type, &val, &interval))
- return FALSE;
-
- val= other->value;
-
- if ((get_interval_value(other->args[1], other->int_type, &val,
- &other_interval)) ||
- ((date_sub_interval ^ interval.neg) ^
- (other->date_sub_interval ^ other_interval.neg)))
- return FALSE;
-
- // Assume comparing same types here due to earlier check
- return memcmp(&interval, &other_interval, sizeof(INTERVAL)) == 0;
+ if (!Item_func::eq(item, binary_cmp))
+ return 0;
+ return ((int_type == other->int_type) &&
+ (date_sub_interval == other->date_sub_interval));
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index ae0ca1a0445..69c8ec5959a 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -39,6 +39,7 @@ public:
{
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -53,6 +54,7 @@ public:
decimals=0;
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -69,6 +71,7 @@ public:
maybe_null=1;
}
enum_monotonicity_info get_monotonicity_info() const;
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -84,6 +87,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -108,6 +112,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -140,6 +145,7 @@ public:
max_length=3*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -155,6 +161,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -170,6 +177,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -185,6 +193,7 @@ public:
max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -200,6 +209,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -215,6 +225,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_yearweek :public Item_int_func
@@ -229,6 +240,7 @@ public:
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -245,6 +257,7 @@ public:
max_length=4*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -274,6 +287,7 @@ public:
max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_dayname :public Item_func_weekday
@@ -306,6 +320,7 @@ public:
decimals=0;
max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -320,6 +335,7 @@ public:
decimals=0;
max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -526,6 +542,7 @@ public:
Item_func_from_days(Item *a) :Item_date(a) {}
const char *func_name() const { return "from_days"; }
bool get_date(TIME *res, uint fuzzy_date);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -543,6 +560,7 @@ public:
void fix_length_and_dec();
uint format_length(const String *format);
bool eq(const Item *item, bool binary_cmp) const;
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -561,6 +579,7 @@ class Item_func_from_unixtime :public Item_date_func
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec();
bool get_date(TIME *res, uint fuzzy_date);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -627,6 +646,7 @@ public:
{
return tmp_table_field_from_field_type(table, 0);
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -649,6 +669,7 @@ public:
bool get_date(TIME *res, uint fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -666,6 +687,7 @@ class Item_extract :public Item_int_func
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -702,6 +724,7 @@ public:
max_length=args[0]->max_length;
maybe_null= 1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -721,6 +744,7 @@ public:
String *val_str(String *a);
void fix_length_and_dec();
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -792,6 +816,7 @@ public:
{
return tmp_table_field_from_field_type(table, 0);
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -814,6 +839,7 @@ public:
}
void print(String *str);
const char *func_name() const { return "add_time"; }
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_timediff :public Item_str_func
@@ -853,6 +879,7 @@ public:
{
return tmp_table_field_from_field_type(table, 0);
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
class Item_func_microsecond :public Item_int_func
@@ -866,6 +893,7 @@ public:
decimals=0;
maybe_null=1;
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -883,6 +911,7 @@ public:
maybe_null=1;
}
void print(String *str);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
@@ -929,6 +958,7 @@ public:
{
return tmp_table_field_from_field_type(table, 1);
}
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index bc47e9c5bb1..e11b4eac1e2 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -42,6 +42,7 @@ public:
Item_func_xml_extractvalue(Item *a,Item *b) :Item_xml_str_func(a,b) {}
const char *func_name() const { return "extractvalue"; }
String *val_str(String *);
+ bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
diff --git a/sql/key.cc b/sql/key.cc
index a407fff4840..11dd267875f 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -301,14 +301,26 @@ bool key_cmp_if_same(TABLE *table,const byte *key,uint idx,uint key_length)
return 0;
}
- /* unpack key-fields from record to some buffer */
- /* This is used to get a good error message */
+/*
+ unpack key-fields from record to some buffer
+
+ SYNOPSIS
+ key_unpack()
+ to Store value here in an easy to read form
+ table Table to use
+ idx Key number
+
+ NOTES
+ This is used mainly to get a good error message
+ We temporary change the column bitmap so that all columns are readable.
+*/
void key_unpack(String *to,TABLE *table,uint idx)
{
KEY_PART_INFO *key_part,*key_part_end;
Field *field;
String tmp;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
DBUG_ENTER("key_unpack");
to->length(0);
@@ -337,6 +349,7 @@ void key_unpack(String *to,TABLE *table,uint idx)
else
to->append(STRING_WITH_LEN("???"));
}
+ dbug_tmp_restore_column_map(table->read_set, old_map);
DBUG_VOID_RETURN;
}
@@ -373,7 +386,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
key is not updated
*/
if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
- (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
+ (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
return check_if_key_used(table, table->s->primary_key, fields);
return 0;
}
diff --git a/sql/lex.h b/sql/lex.h
index 555a68dc388..67daf4566f8 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -133,6 +133,7 @@ static SYMBOL symbols[] = {
{ "CONSTRAINT", SYM(CONSTRAINT)},
{ "CONTAINS", SYM(CONTAINS_SYM)},
{ "CONTINUE", SYM(CONTINUE_SYM)},
+ { "CONTRIBUTORS", SYM(CONTRIBUTORS_SYM)},
{ "CONVERT", SYM(CONVERT_SYM)},
{ "CREATE", SYM(CREATE)},
{ "CROSS", SYM(CROSS)},
@@ -453,6 +454,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM)},
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
{ "SCHEDULE", SYM(SCHEDULE_SYM)},
+ { "SCHEDULER", SYM(SCHEDULER_SYM)},
{ "SCHEMA", SYM(DATABASE)},
{ "SCHEMAS", SYM(DATABASES)},
{ "SECOND", SYM(SECOND_SYM)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 5a6cd58dd56..80861e3beb5 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1174,16 +1174,17 @@ bool lock_global_read_lock(THD *thd)
if (!thd->global_read_lock)
{
+ const char *old_message;
(void) pthread_mutex_lock(&LOCK_global_read_lock);
- const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
- "Waiting to get readlock");
+ old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
+ "Waiting to get readlock");
DBUG_PRINT("info",
("waiting_for: %d protect_against: %d",
waiting_for_read_lock, protect_against_global_read_lock));
waiting_for_read_lock++;
while (protect_against_global_read_lock && !thd->killed)
- pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
+ pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
waiting_for_read_lock--;
if (thd->killed)
{
@@ -1205,9 +1206,15 @@ bool lock_global_read_lock(THD *thd)
DBUG_RETURN(0);
}
+
void unlock_global_read_lock(THD *thd)
{
uint tmp;
+ DBUG_ENTER("unlock_global_read_lock");
+ DBUG_PRINT("info",
+ ("global_read_lock: %u global_read_lock_blocks_commit: %u",
+ global_read_lock, global_read_lock_blocks_commit));
+
pthread_mutex_lock(&LOCK_global_read_lock);
tmp= --global_read_lock;
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
@@ -1215,8 +1222,13 @@ void unlock_global_read_lock(THD *thd)
pthread_mutex_unlock(&LOCK_global_read_lock);
/* Send the signal outside the mutex to avoid a context switch */
if (!tmp)
- pthread_cond_broadcast(&COND_refresh);
+ {
+ DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock"));
+ pthread_cond_broadcast(&COND_global_read_lock);
+ }
thd->global_read_lock= 0;
+
+ DBUG_VOID_RETURN;
}
#define must_wait (global_read_lock && \
@@ -1254,11 +1266,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
*/
DBUG_RETURN(is_not_commit);
}
- old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
+ old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
"Waiting for release of readlock");
while (must_wait && ! thd->killed &&
(!abort_on_refresh || thd->version == refresh_version))
- (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock);
+ {
+ DBUG_PRINT("signal", ("Waiting for COND_global_read_lock"));
+ (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
+ DBUG_PRINT("signal", ("Got COND_global_read_lock"));
+ }
if (thd->killed)
result=1;
}
@@ -1287,7 +1303,7 @@ void start_waiting_global_read_lock(THD *thd)
(waiting_for_read_lock || global_read_lock_blocks_commit));
(void) pthread_mutex_unlock(&LOCK_global_read_lock);
if (tmp)
- pthread_cond_broadcast(&COND_refresh);
+ pthread_cond_broadcast(&COND_global_read_lock);
DBUG_VOID_RETURN;
}
@@ -1309,10 +1325,10 @@ bool make_global_read_lock_block_commit(THD *thd)
/* For testing we set up some blocking, to see if we can be killed */
DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
protect_against_global_read_lock++;);
- old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
+ old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
"Waiting for all running commits to finish");
while (protect_against_global_read_lock && !thd->killed)
- pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
+ pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
protect_against_global_read_lock--;);
if ((error= test(thd->killed)))
diff --git a/sql/log.cc b/sql/log.cc
index fa86064682d..5a17ef817d0 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -47,7 +47,7 @@ ulong sync_binlog_counter= 0;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
-static bool binlog_init();
+static int binlog_init();
static int binlog_close_connection(THD *thd);
static int binlog_savepoint_set(THD *thd, void *sv);
static int binlog_savepoint_rollback(THD *thd, void *sv);
@@ -55,6 +55,14 @@ static int binlog_commit(THD *thd, bool all);
static int binlog_rollback(THD *thd, bool all);
static int binlog_prepare(THD *thd, bool all);
+sql_print_message_func sql_print_message_handlers[3] =
+{
+ sql_print_information,
+ sql_print_warning,
+ sql_print_error
+};
+
+
/*
This is a POD. Please keep it that way!
@@ -70,49 +78,7 @@ struct binlog_trx_data {
Rows_log_event *pending; // The pending binrows event
};
-static const char binlog_hton_name[]= "binlog";
-static const char binlog_hton_comment[]=
- "This is a meta storage engine to represent the binlog in a transaction";
-
-handlerton binlog_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- binlog_hton_name,
- SHOW_OPTION_YES,
- binlog_hton_comment,
- DB_TYPE_BINLOG, /* IGNORE for now */
- binlog_init,
- 0,
- sizeof(my_off_t), /* savepoint size = binlog offset */
- binlog_close_connection,
- binlog_savepoint_set,
- binlog_savepoint_rollback,
- NULL, /* savepoint_release */
- binlog_commit,
- binlog_rollback,
- binlog_prepare,
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- NULL, /* Create a new handler */
- NULL, /* Drop a database */
- NULL, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill FILES table */
- HTON_NOT_USER_SELECTABLE | HTON_HIDDEN,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
-
-
+handlerton binlog_hton;
/*
Open log table of a given type (general or slow log)
@@ -201,8 +167,10 @@ bool Log_to_csv_event_handler::open_log_table(uint log_type)
table->table->file->ha_rnd_init(0))
error= TRUE;
else
+ {
+ table->table->use_all_columns();
table->table->locked_by_logger= TRUE;
-
+ }
/* restore thread settings */
if (curr)
curr->store_globals();
@@ -1058,9 +1026,20 @@ void Log_to_csv_event_handler::
should be moved here.
*/
-bool binlog_init()
+int binlog_init()
{
- return !opt_bin_log;
+
+ binlog_hton.state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
+ binlog_hton.db_type=DB_TYPE_BINLOG;
+ binlog_hton.savepoint_offset= sizeof(my_off_t);
+ binlog_hton.close_connection= binlog_close_connection;
+ binlog_hton.savepoint_set= binlog_savepoint_set;
+ binlog_hton.savepoint_rollback= binlog_savepoint_rollback;
+ binlog_hton.commit= binlog_commit;
+ binlog_hton.rollback= binlog_rollback;
+ binlog_hton.prepare= binlog_prepare;
+ binlog_hton.flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
+ return 0;
}
static int binlog_close_connection(THD *thd)
@@ -1176,7 +1155,8 @@ static int binlog_rollback(THD *thd, bool all)
table. Such cases should be rare (updating a
non-transactional table inside a transaction...)
*/
- if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ if (unlikely(thd->options & (OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG)))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
@@ -1237,7 +1217,8 @@ static int binlog_savepoint_rollback(THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
- if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ if (unlikely(thd->options &
+ (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)))
{
int const error=
thd->binlog_query(THD::STMT_QUERY_TYPE,
@@ -2664,8 +2645,9 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans)
{
int error;
DBUG_ENTER("THD::binlog_write_table_map");
- DBUG_PRINT("enter", ("table: %p (%s: #%u)",
- table, table->s->table_name, table->s->table_map_id));
+ DBUG_PRINT("enter", ("table: %0xlx (%s: #%u)",
+ (long) table, table->s->table_name,
+ table->s->table_map_id));
/* Pre-conditions */
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
@@ -2678,7 +2660,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans)
the_event(this, table, table->s->table_map_id, is_trans, flags);
if (is_trans)
- trans_register_ha(this, options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN),
+ trans_register_ha(this,
+ (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) != 0,
&binlog_hton);
if ((error= mysql_bin_log.write(&the_event)))
@@ -2869,7 +2852,7 @@ bool MYSQL_LOG::write(Log_event *event_info)
}
#endif /* HAVE_REPLICATION */
-#ifdef USING_TRANSACTIONS
+#if defined(USING_TRANSACTIONS) && defined(HAVE_ROW_BASED_REPLICATION)
/*
Should we write to the binlog cache or to the binlog on disk?
Write to the binlog cache if:
@@ -2881,10 +2864,8 @@ bool MYSQL_LOG::write(Log_event *event_info)
*/
if (opt_using_transactions && thd)
{
-#ifdef HAVE_ROW_BASED_REPLICATION
if (thd->binlog_setup_trx_data())
goto err;
-#endif /*HAVE_ROW_BASED_REPLICATION*/
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton.slot];
@@ -2894,7 +2875,7 @@ bool MYSQL_LOG::write(Log_event *event_info)
if (event_info->get_cache_stmt() && !trans_log_in_use)
trans_register_ha(thd,
(thd->options &
- (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)),
+ (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) != 0,
&binlog_hton);
if (event_info->get_cache_stmt() || trans_log_in_use)
{
@@ -2908,7 +2889,7 @@ bool MYSQL_LOG::write(Log_event *event_info)
LOCK_log.
*/
}
-#endif
+#endif /* USING_TRANSACTIONS && HAVE_ROW_BASED_REPLICATION */
DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
/*
@@ -2938,6 +2919,11 @@ bool MYSQL_LOG::write(Log_event *event_info)
}
if (thd->insert_id_used)
{
+ /*
+ If the auto_increment was second in a table's index (possible with
+ MyISAM or BDB) (table->next_number_key_offset != 0), such event is
+ in fact not necessary. We could avoid logging it.
+ */
Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
if (e.write(file))
goto err;
@@ -4364,16 +4350,19 @@ err1:
return 1;
}
+struct st_mysql_storage_engine binlog_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &binlog_hton };
mysql_declare_plugin(binlog)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &binlog_hton,
- binlog_hton_name,
+ &binlog_storage_engine,
+ "binlog",
"MySQL AB",
- binlog_hton_comment,
- NULL, /* Plugin Init */
+ "This is a pseudo storage engine to represent the binlog in a transaction",
+ binlog_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
+ 0
}
mysql_declare_plugin_end;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ab9fa2975a1..78ab54aeb79 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1744,21 +1744,22 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query
{
if (flags2_inited)
/*
- all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
- take their value from flags2.
+ all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
+ must take their value from flags2.
*/
- thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
+ thd->options= flags2|(thd->options & ~OPTIONS_WRITTEN_TO_BIN_LOG);
/*
else, we are in a 3.23/4.0 binlog; we previously received a
- Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do.
+ Rotate_log_event which reset thd->options and sql_mode etc, so
+ nothing to do.
*/
/*
We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
force us to ignore the dir too. Imagine you are a ring of machines, and
- one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
- on this machine; you don't want it to propagate elsewhere (you don't want
- all slaves to start ignoring the dirs).
+ one has a disk problem so that you temporarily need
+ IGNORE_DIR_IN_CREATE on this machine; you don't want it to propagate
+ elsewhere (you don't want all slaves to start ignoring the dirs).
*/
if (sql_mode_inited)
thd->variables.sql_mode=
@@ -3264,8 +3265,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
rli->notify_group_master_log_name_update();
rli->group_master_log_pos= pos;
rli->group_relay_log_pos= rli->event_relay_log_pos;
- DBUG_PRINT("info", ("group_master_log_name: '%s' group_master_log_pos:\
-%lu",
+ DBUG_PRINT("info", ("group_master_log_name: '%s' "
+ "group_master_log_pos: %lu",
rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
/*
@@ -3481,24 +3482,12 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
Xid_log_event methods
**************************************************************************/
-#if !defined(DBUG_OFF) && !defined(MYSQL_CLIENT)
-/*
- This static class member could be removed when mysqltest is made to support
- a --replace-regex command: then tests which have XIDs in their output can
- use this command to suppress non-deterministic XID values.
-*/
-my_bool Xid_log_event::show_xid;
-#endif
-
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Xid_log_event::pack_info(Protocol *protocol)
{
char buf[128], *pos;
pos= strmov(buf, "COMMIT /* xid=");
-#if !defined(DBUG_OFF) && !defined(MYSQL_CLIENT)
- if (show_xid)
-#endif
- pos= longlong10_to_str(xid, pos, 10);
+ pos= longlong10_to_str(xid, pos, 10);
pos= strmov(pos, " */");
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
@@ -5212,8 +5201,9 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
log only the primary key value instead of the entire "before image". This
would save binlog space. TODO
*/
- DBUG_ENTER("Rows_log_event::do_add_row_data(byte *data, my_size_t length)");
- DBUG_PRINT("enter", ("row_data= %p, length= %lu", row_data, length));
+ DBUG_ENTER("Rows_log_event::do_add_row_data");
+ DBUG_PRINT("enter", ("row_data: 0x%lx length: %lu", (ulong) row_data,
+ length));
DBUG_DUMP("row_data", (const char*)row_data, min(length, 32));
DBUG_ASSERT(m_rows_buf <= m_rows_cur);
@@ -5268,7 +5258,7 @@ static char const *unpack_row(TABLE *table,
{
DBUG_ASSERT(record && row);
- MY_BITMAP *write_set= table->file->write_set;
+ MY_BITMAP *write_set= table->write_set;
my_size_t const n_null_bytes= table->s->null_bytes;
my_ptrdiff_t const offset= record - (byte*) table->record[0];
@@ -5281,13 +5271,13 @@ static char const *unpack_row(TABLE *table,
{
Field *const f= *field_ptr;
- if (bitmap_is_set(cols, field_ptr - begin_ptr))
+ if (bitmap_is_set(cols, (uint) (field_ptr - begin_ptr)))
{
/* Field...::unpack() cannot return 0 */
ptr= f->unpack(f->ptr + offset, ptr);
}
else
- bitmap_clear_bit(write_set, (field_ptr - begin_ptr) + 1);
+ bitmap_clear_bit(write_set, (uint) (field_ptr - begin_ptr));
}
return ptr;
}
@@ -5443,7 +5433,8 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
error= do_before_row_operations(table);
- while (error == 0 && row_start < (const char*)m_rows_end) {
+ while (error == 0 && row_start < (const char*) m_rows_end)
+ {
char const *row_end= do_prepare_row(thd, table, row_start);
DBUG_ASSERT(row_end != NULL); // cannot happen
DBUG_ASSERT(row_end <= (const char*)m_rows_end);
@@ -5478,8 +5469,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
rli->abort_slave=1;);
error= do_after_row_operations(table, error);
if (!cache_stmt)
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
-
+ {
+ DBUG_PRINT("info", ("Marked that we need to keep log"));
+ thd->options|= OPTION_KEEP_LOG;
+ }
}
if (error)
@@ -6142,7 +6135,7 @@ int Write_rows_log_event::do_before_row_operations(TABLE *table)
how many rows are going to be inserted, then it can allocate needed memory
from the start.
*/
- table->file->start_bulk_insert(0);
+ table->file->ha_start_bulk_insert(0);
/*
We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill
any TIMESTAMP column with data from the row but instead will use
@@ -6165,7 +6158,7 @@ int Write_rows_log_event::do_before_row_operations(TABLE *table)
int Write_rows_log_event::do_after_row_operations(TABLE *table, int error)
{
if (error == 0)
- error= table->file->end_bulk_insert();
+ error= table->file->ha_end_bulk_insert();
return error;
}
@@ -6267,9 +6260,9 @@ replace_record(THD *thd, TABLE *table)
- use index_read_idx() with the key that is duplicated, to
retrieve the offending row.
*/
- if (table->file->table_flags() & HA_DUPP_POS)
+ if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
{
- error= table->file->rnd_pos(table->record[1], table->file->dupp_ref);
+ error= table->file->rnd_pos(table->record[1], table->file->dup_ref);
if (error)
return error;
}
@@ -6386,16 +6379,17 @@ static bool record_compare(TABLE *table)
to find (and fetch) the row. If the engine allows random access of the
records, a combination of position() and rnd_pos() will be used.
*/
+
static int find_and_fetch_row(TABLE *table, byte *key)
{
DBUG_ENTER("find_and_fetch_row(TABLE *table, byte *key, byte *record)");
- DBUG_PRINT("enter", ("table=%p, key=%p, record=%p",
- table, key, table->record[1]));
+ DBUG_PRINT("enter", ("table: 0x%lx, key: 0x%lx record: 0x%lx",
+ (long) table, (long) key, (long) table->record[1]));
DBUG_ASSERT(table->in_use != NULL);
- if ((table->file->table_flags() & HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS)
- && table->s->primary_key < MAX_KEY)
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
+ table->s->primary_key < MAX_KEY)
{
/*
Use a more efficient method to fetch the record given by
@@ -6411,15 +6405,15 @@ static int find_and_fetch_row(TABLE *table, byte *key)
DBUG_ASSERT(table->record[1]);
/* We need to retrieve all fields */
- table->file->ha_set_all_bits_in_read_set();
+ /* TODO: Move this out from this function to main loop */
+ table->use_all_columns();
if (table->s->keys > 0)
{
int error;
/* We have a key: search the table using the index */
- if (!table->file->inited)
- if ((error= table->file->ha_index_init(0, FALSE)))
- return error;
+ if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE)))
+ return error;
/*
We need to set the null bytes to ensure that the filler bit are
@@ -6452,7 +6446,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
comparison of non-PK columns to decide if the correct record is
found. I can see no scenario where it would be incorrect to
chose the row to change only using a PK or an UNNI.
- */
+ */
if (table->key_info->flags & HA_NOSAME)
{
table->file->ha_index_end();
@@ -6576,7 +6570,7 @@ int Delete_rows_log_event::do_before_row_operations(TABLE *table)
{
DBUG_ASSERT(m_memory == NULL);
- if ((table->file->table_flags() & HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS) &&
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
table->s->primary_key < MAX_KEY)
{
/*
@@ -6650,19 +6644,18 @@ char const *Delete_rows_log_event::do_prepare_row(THD *thd, TABLE *table,
int Delete_rows_log_event::do_exec_row(TABLE *table)
{
+ int error;
DBUG_ASSERT(table != NULL);
- int error= find_and_fetch_row(table, m_key);
- if (error)
- return error;
-
- /*
- Now we should have the right row to delete. We are using
- record[0] since it is guaranteed to point to a record with the
- correct value.
- */
- error= table->file->ha_delete_row(table->record[0]);
-
+ if (!(error= find_and_fetch_row(table, m_key)))
+ {
+ /*
+ Now we should have the right row to delete. We are using
+ record[0] since it is guaranteed to point to a record with the
+ correct value.
+ */
+ error= table->file->ha_delete_row(table->record[0]);
+ }
return error;
}
diff --git a/sql/log_event.h b/sql/log_event.h
index b24686514e3..36933f4a7dd 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1221,9 +1221,6 @@ class Xid_log_event: public Log_event
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
-#if !defined(DBUG_OFF) && !defined(MYSQL_CLIENT)
- static my_bool show_xid;
-#endif
};
/*****************************************************************************
@@ -1635,6 +1632,8 @@ public:
#endif
char *str_to_hex(char *to, const char *from, uint len);
+#ifdef HAVE_ROW_BASED_REPLICATION
+
/*****************************************************************************
Table map log event class
@@ -1643,7 +1642,6 @@ char *str_to_hex(char *to, const char *from, uint len);
identifier (an integer number).
****************************************************************************/
-
class Table_map_log_event : public Log_event
{
public:
@@ -1750,6 +1748,7 @@ private:
****************************************************************************/
+
class Rows_log_event : public Log_event
{
public:
@@ -2121,5 +2120,6 @@ private:
#endif
};
+#endif /* HAVE_ROW_BASED_REPLICATION */
#endif /* _log_event_h */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 627ffae53fc..76d8aa18f59 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -79,7 +79,8 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
-void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
+void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
@@ -278,9 +279,9 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define OPTION_BEGIN (LL(1) << 20) // THD, intern
#define OPTION_TABLE_LOCK (LL(1) << 21) // THD, intern
#define OPTION_QUICK (LL(1) << 22) // SELECT (for DELETE)
+#define OPTION_KEEP_LOG (LL(1) << 23) // Keep binlog on rollback
-/* Thr following is used to detect a conflict with DISTINCT
- in the user query has requested */
+/* The following is used to detect a conflict with DISTINCT */
#define SELECT_ALL (LL(1) << 24) // SELECT, user, parser
/* Set if we are updating a non-transaction safe table */
@@ -488,6 +489,7 @@ inline THD *_current_thd(void)
my_bool thd_in_lock_tables(const THD *thd);
my_bool thd_tablespace_op(const THD *thd);
const char *thd_proc_info(THD *thd, const char *info);
+void **thd_ha_data(const THD *thd, const struct handlerton *hton);
/*
External variables
@@ -502,13 +504,13 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "sql_list.h"
#include "sql_map.h"
#include "my_decimal.h"
+#include "sql_plugin.h"
#include "handler.h"
#include "parse_file.h"
#include "table.h"
#include "sql_error.h"
#include "field.h" /* Field definitions */
#include "protocol.h"
-#include "sql_plugin.h"
#include "sql_udf.h"
#include "sql_partition.h"
@@ -847,6 +849,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
+ Field **def_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field,
@@ -998,6 +1001,7 @@ int mysql_find_files(THD *thd,List<char> *files, const char *db,
const char *path, const char *wild, bool dir);
bool mysqld_show_storage_engines(THD *thd);
bool mysqld_show_authors(THD *thd);
+bool mysqld_show_contributors(THD *thd);
bool mysqld_show_privileges(THD *thd);
bool mysqld_show_column_types(THD *thd);
bool mysqld_help (THD *thd, const char *text);
@@ -1102,20 +1106,28 @@ bool insert_fields(THD *thd, Name_resolution_context *context,
List_iterator<Item> *it, bool any_privileges);
bool setup_tables(THD *thd, Name_resolution_context *context,
List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
- Item **conds, TABLE_LIST **leaves, bool select_insert);
+ TABLE_LIST **leaves, bool select_insert);
+bool setup_tables_and_check_access(THD *thd,
+ Name_resolution_context *context,
+ List<TABLE_LIST> *from_clause,
+ TABLE_LIST *tables,
+ TABLE_LIST **leaves,
+ bool select_insert,
+ ulong want_access);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
bool setup_fields(THD *thd, Item** ref_pointer_array,
- List<Item> &item, ulong set_query_id,
+ List<Item> &item, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func);
inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
- List<Item> &item, ulong set_query_id,
- List<Item> *sum_func_list,
- bool allow_sum_func)
+ List<Item> &item,
+ enum_mark_columns mark_used_columns,
+ List<Item> *sum_func_list,
+ bool allow_sum_func)
{
bool res;
thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list,
+ res= setup_fields(thd, ref_pointer_array, item, mark_used_columns, sum_func_list,
allow_sum_func);
thd->lex->select_lex.no_wrap_view_item= FALSE;
return res;
@@ -1378,10 +1390,13 @@ bool init_errmessage(void);
#endif /* MYSQL_SERVER */
void sql_perror(const char *message);
+
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
void sql_print_error(const char *format, ...);
void sql_print_warning(const char *format, ...);
void sql_print_information(const char *format, ...);
+typedef void (*sql_print_message_func)(const char *format, ...);
+extern sql_print_message_func sql_print_message_handlers[];
/* type of the log table */
#define QUERY_LOG_SLOW 1
@@ -1498,6 +1513,7 @@ extern my_bool locked_in_memory;
extern bool opt_using_transactions, mysqld_embedded;
extern bool using_update_log, opt_large_files, server_id_supplied;
extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log;
+extern my_bool opt_log_queries_not_using_indexes;
extern bool opt_disable_networking, opt_skip_show_db;
extern my_bool opt_character_set_client_handshake;
extern bool volatile abort_loop, shutdown_in_progress, grant_option;
@@ -1542,6 +1558,7 @@ extern pthread_cond_t COND_server_started;
extern int mysqld_server_started;
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
+extern pthread_cond_t COND_global_read_lock;
extern pthread_attr_t connection_attrib;
extern I_List<THD> threads;
extern I_List<NAMED_LIST> key_caches;
@@ -1758,7 +1775,8 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
void end_read_record(READ_RECORD *info);
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
uint s_length, SQL_SELECT *select,
- ha_rows max_rows, ha_rows *examined_rows);
+ ha_rows max_rows, bool sort_positions,
+ ha_rows *examined_rows);
void filesort_free_buffers(TABLE *table);
void change_double_for_sort(double nr,byte *to);
double my_double_round(double value, int dec, bool truncate);
@@ -1936,7 +1954,6 @@ inline int hexchar_to_int(char c)
return -1;
}
-
/*
Some functions that are different in the embedded library and the normal
server
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 3cca41fa0e5..56c3b1857a8 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -318,7 +318,6 @@ static bool volatile ready_to_exit;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_bdb, opt_isam, opt_ndbcluster;
static my_bool opt_short_log_format= 0;
-static my_bool opt_log_queries_not_using_indexes= 0;
static uint kill_cached_threads, wake_thread;
static ulong killed_threads, thread_created;
static ulong max_used_connections;
@@ -330,7 +329,7 @@ static char *opt_init_slave, *language_ptr, *opt_init_connect;
static char *default_character_set_name;
static char *character_set_filesystem_name;
static char *my_bind_addr_str;
-static char *default_collation_name;
+static char *default_collation_name, *default_storage_engine_str;
static char mysql_data_home_buff[2];
static struct passwd *user_info;
static I_List<THD> thread_cache;
@@ -344,6 +343,7 @@ static my_bool opt_sync_bdb_logs;
/* Global variables */
bool opt_log, opt_update_log, opt_bin_log, opt_slow_log;
+my_bool opt_log_queries_not_using_indexes= 0;
bool opt_error_log= IF_WIN(1,0);
bool opt_disable_networking=0, opt_skip_show_db=0;
my_bool opt_character_set_client_handshake= 1;
@@ -605,7 +605,7 @@ pthread_mutex_t LOCK_prepared_stmt_count;
pthread_mutex_t LOCK_des_key_file;
#endif
rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
-pthread_cond_t COND_refresh,COND_thread_count;
+pthread_cond_t COND_refresh, COND_thread_count, COND_global_read_lock;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
pthread_mutex_t LOCK_server_started;
@@ -693,6 +693,7 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
+#define SSL_VARS_NOT_STATIC
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
#include <openssl/crypto.h>
@@ -863,8 +864,8 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
- /* We skip slave threads on this first loop through. */
- if (tmp->slave_thread)
+ /* We skip slave threads & scheduler on this first loop through. */
+ if (tmp->slave_thread || tmp->system_thread == SYSTEM_THREAD_EVENT_SCHEDULER)
continue;
tmp->killed= THD::KILL_CONNECTION;
@@ -883,6 +884,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
+ Events::shutdown();
end_slave();
if (thread_count)
@@ -1022,7 +1024,20 @@ void kill_mysql(void)
DBUG_VOID_RETURN;
}
- /* Force server down. kill all connections and threads and exit */
+/*
+ Force server down. Kill all connections and threads and exit
+
+ SYNOPSIS
+ kill_server
+
+ sig_ptr Signal number that caused kill_server to be called.
+
+ NOTE!
+ A signal number of 0 mean that the function was not called
+ from a signal handler and there is thus no signal to block
+ or stop, we just want to kill the server.
+
+*/
#if defined(__NETWARE__)
extern "C" void kill_server(int sig_ptr)
@@ -1043,7 +1058,8 @@ static void __cdecl kill_server(int sig_ptr)
RETURN_FROM_KILL_SERVER;
kill_in_progress=TRUE;
abort_loop=1; // This should be set
- my_sigset(sig,SIG_IGN);
+ if (sig != 0) // 0 is not a valid signal number
+ my_sigset(sig,SIG_IGN);
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
@@ -1065,7 +1081,11 @@ static void __cdecl kill_server(int sig_ptr)
my_thread_init(); // If this is a new thread
#endif
close_connections();
- if (sig != MYSQL_KILL_SIGNAL && sig != 0)
+ if (sig != MYSQL_KILL_SIGNAL &&
+#ifdef __WIN__
+ sig != SIGINT && /* Bug#18235 */
+#endif
+ sig != 0)
unireg_abort(1); /* purecov: inspected */
else
unireg_end();
@@ -1297,6 +1317,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
+ Events::destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@@ -1318,6 +1339,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
+ (void) pthread_cond_destroy(&COND_global_read_lock);
(void) pthread_cond_destroy(&COND_thread_cache);
(void) pthread_cond_destroy(&COND_flush_thread_cache);
(void) pthread_cond_destroy(&COND_manager);
@@ -1740,13 +1762,11 @@ void end_thread(THD *thd, bool put_in_cache)
}
}
- DBUG_PRINT("info", ("sending a broadcast"));
-
/* Tell main we are ready */
(void) pthread_mutex_unlock(&LOCK_thread_count);
/* It's safe to broadcast outside a lock (COND... is not deleted here) */
+ DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
(void) pthread_cond_broadcast(&COND_thread_count);
- DBUG_PRINT("info", ("unlocked thread_count mutex"));
#ifdef ONE_THREAD
if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux
#endif
@@ -2452,10 +2472,12 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
if (thd->lex->current_select &&
thd->lex->current_select->no_error && !thd->is_fatal_error)
{
- DBUG_PRINT("error", ("Error converted to warning: current_select: no_error %d fatal_error: %d",
- (thd->lex->current_select ?
- thd->lex->current_select->no_error : 0),
- (int) thd->is_fatal_error));
+ DBUG_PRINT("error",
+ ("Error converted to warning: current_select: no_error %d "
+ "fatal_error: %d",
+ (thd->lex->current_select ?
+ thd->lex->current_select->no_error : 0),
+ (int) thd->is_fatal_error));
}
else
{
@@ -2634,12 +2656,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
if (add_status_vars(status_vars))
return 1; // an error was already reported
- if (plugin_init())
- {
- sql_print_error("Failed to init plugins.");
- return 1;
- }
-
load_defaults(conf_file_name, groups, &argc, &argv);
defaults_argv=argv;
get_options(argc,argv);
@@ -2842,6 +2858,7 @@ static int init_thread_environment()
(void) my_rwlock_init(&LOCK_grant, NULL);
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
+ (void) pthread_cond_init(&COND_global_read_lock,NULL);
(void) pthread_cond_init(&COND_thread_cache,NULL);
(void) pthread_cond_init(&COND_flush_thread_cache,NULL);
(void) pthread_cond_init(&COND_manager,NULL);
@@ -2852,6 +2869,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
+ Events::init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@@ -2997,7 +3015,6 @@ static int init_server_components()
#ifdef HAVE_REPLICATION
init_slave_list();
#endif
- init_events();
/* Setup logs */
@@ -3155,6 +3172,12 @@ server.");
using_update_log=1;
}
+ if (plugin_init())
+ {
+ sql_print_error("Failed to init plugins.");
+ return 1;
+ }
+
/* We have to initialize the storage engines before CSV logging */
if (ha_init())
{
@@ -3201,15 +3224,27 @@ server.");
/*
Check that the default storage engine is actually available.
*/
- if (!ha_storage_engine_is_enabled(global_system_variables.table_type))
{
- if (!opt_bootstrap)
+ LEX_STRING name= { default_storage_engine_str,
+ strlen(default_storage_engine_str) };
+ handlerton *hton= ha_resolve_by_name(0, &name);
+ if (hton == NULL)
{
- sql_print_error("Default storage engine (%s) is not available",
- global_system_variables.table_type->name);
+ sql_print_error("Unknown/unsupported table type: %s",
+ default_storage_engine_str);
unireg_abort(1);
}
- global_system_variables.table_type= &myisam_hton;
+ if (!ha_storage_engine_is_enabled(hton))
+ {
+ if (!opt_bootstrap)
+ {
+ sql_print_error("Default storage engine (%s) is not available",
+ default_storage_engine_str);
+ unireg_abort(1);
+ }
+ hton= &myisam_hton;
+ }
+ global_system_variables.table_type= hton;
}
tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
@@ -3621,6 +3656,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
mysqld_server_started= 1;
pthread_cond_signal(&COND_server_started);
+ if (!opt_noacl)
+ {
+ Events::init();
+ }
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
#else
@@ -3672,7 +3711,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
clean_up(1);
wait_for_signal_thread_to_end();
clean_up_mutexes();
- shutdown_events();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(0);
@@ -4663,7 +4701,7 @@ enum options_mysqld
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
OPT_HAVE_NAMED_PIPE,
- OPT_DO_PSTACK, OPT_EVENT_EXECUTOR, OPT_REPORT_HOST,
+ OPT_DO_PSTACK, OPT_EVENT_SCHEDULER, OPT_REPORT_HOST,
OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
OPT_SHOW_SLAVE_AUTH_INFO,
OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
@@ -4720,6 +4758,7 @@ enum options_mysqld
OPT_INNODB_FILE_IO_THREADS,
OPT_INNODB_LOCK_WAIT_TIMEOUT,
OPT_INNODB_THREAD_CONCURRENCY,
+ OPT_INNODB_COMMIT_CONCURRENCY,
OPT_INNODB_FORCE_RECOVERY,
OPT_INNODB_STATUS_FILE,
OPT_INNODB_MAX_DIRTY_PAGES_PCT,
@@ -4881,14 +4920,6 @@ Disable with --skip-bdb (will save memory).",
{"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
"Tells the master that updates to the given database should not be logged tothe binary log.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#if !defined(DBUG_OFF) && !defined(MYSQL_CLIENT)
- {"binlog-show-xid", OPT_BINLOG_SHOW_XID,
- "Option used by mysql-test for debugging and testing: "
- "do not display the XID in SHOW BINLOG EVENTS; "
- "may be removed in future versions",
- (gptr*) &Xid_log_event::show_xid, (gptr*) &Xid_log_event::show_xid,
- 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
-#endif
#ifdef HAVE_ROW_BASED_REPLICATION
{"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
"The maximum size of a row-based binary log event in bytes. Rows will be "
@@ -4955,7 +4986,8 @@ Disable with --skip-bdb (will save memory).",
"Set the default storage engine (table type) for tables.", 0, 0,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-table-type", OPT_STORAGE_ENGINE,
- "(deprecated) Use --default-storage-engine.", 0, 0,
+ "(deprecated) Use --default-storage-engine.",
+ (gptr*)default_storage_engine_str, (gptr*)default_storage_engine_str,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-time-zone", OPT_DEFAULT_TIME_ZONE, "Set the default time zone.",
(gptr*) &default_tz_name, (gptr*) &default_tz_name,
@@ -4996,12 +5028,12 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &global_system_variables.engine_condition_pushdown,
(gptr*) &global_system_variables.engine_condition_pushdown,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"event-scheduler", OPT_EVENT_EXECUTOR, "Enable/disable the event scheduler.",
- (gptr*) &opt_event_executor, (gptr*) &opt_event_executor, 0, GET_BOOL, NO_ARG,
- 0/*default*/, 0/*min-value*/, 1/*max-value*/, 0, 0, 0},
+ {"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
+ (gptr*) &Events::opt_event_scheduler, (gptr*) &Events::opt_event_scheduler, 0, GET_ULONG,
+ REQUIRED_ARG, 2/*default*/, 0/*min-value*/, 2/*max-value*/, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
+ {"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.",
(gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0,
@@ -5666,7 +5698,6 @@ log and this option does nothing anymore.",
"The buffer that is allocated to cache index and rows for BDB tables.",
(gptr*) &berkeley_cache_size, (gptr*) &berkeley_cache_size, 0, GET_ULL,
REQUIRED_ARG, KEY_CACHE_SIZE, 20*1024, (ulonglong) ~0, 0, IO_SIZE, 0},
- /* QQ: The following should be removed soon! (bdb_max_lock preferred) */
{"bdb_lock_max", OPT_BDB_MAX_LOCK, "Synonym for bdb_max_lock.",
(gptr*) &berkeley_max_lock, (gptr*) &berkeley_max_lock, 0, GET_ULONG,
REQUIRED_ARG, 10000, 0, (long) ~0, 0, 1, 0},
@@ -5783,7 +5814,7 @@ log and this option does nothing anymore.",
(gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0,
GET_LL, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, LONGLONG_MAX, 0,
1024*1024L, 0},
- {"innodb_commit_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
+ {"innodb_commit_concurrency", OPT_INNODB_COMMIT_CONCURRENCY,
"Helps in performance tuning in heavily concurrent environments.",
(gptr*) &srv_commit_concurrency, (gptr*) &srv_commit_concurrency,
0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0},
@@ -5835,7 +5866,7 @@ log and this option does nothing anymore.",
{"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
"Helps in performance tuning in heavily concurrent environments.",
(gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0},
+ 0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0},
{"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
" disable a sleep",
@@ -6984,8 +7015,8 @@ static void mysql_init_variables(void)
sys_charset_system.value= (char*) system_charset_info->csname;
character_set_filesystem_name= (char*) "binary";
-
/* Set default values for some option variables */
+ default_storage_engine_str= (char*) "MyISAM";
global_system_variables.table_type= &myisam_hton;
global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
@@ -7325,6 +7356,24 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
}
#endif
+ case OPT_EVENT_SCHEDULER:
+ if (!argument)
+ Events::opt_event_scheduler= 2;
+ else
+ {
+ int type;
+ if ((type=find_type(argument, &Events::opt_typelib, 1)) <= 0)
+ {
+ fprintf(stderr,"Unknown option to event-scheduler: %s\n",argument);
+ exit(1);
+ }
+ /*
+ type= 1 2 3 4 5 6
+ (OFF | 0) - (ON | 1) - (2 | SUSPEND)
+ */
+ Events::opt_event_scheduler= (type-1) / 2;
+ }
+ break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
@@ -7427,17 +7476,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_BOOTSTRAP:
opt_noacl=opt_bootstrap=1;
break;
- case OPT_STORAGE_ENGINE:
- {
- LEX_STRING name= { argument, strlen(argument) };
- if ((global_system_variables.table_type=
- ha_resolve_by_name(current_thd, &name)) == NULL)
- {
- fprintf(stderr,"Unknown/unsupported table type: %s\n",argument);
- exit(1);
- }
- break;
- }
case OPT_SERVER_ID:
server_id_supplied = 1;
break;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 9713e4bed44..03164827e8f 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -37,9 +37,6 @@
HFTODO this must be hidden if we don't want client capabilities in
embedded library
*/
-#ifdef __WIN__
-#include <winsock.h>
-#endif
#include <my_global.h>
#include <mysql.h>
#include <mysql_embed.h>
@@ -51,6 +48,12 @@
#include <violite.h>
#include <signal.h>
#include <errno.h>
+#ifdef __WIN__
+#include <winsock.h>
+#endif
+#ifdef __NETWARE__
+#include <sys/select.h>
+#endif
#ifdef EMBEDDED_LIBRARY
#undef MYSQL_SERVER
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index af70b9aade7..7fa47b0b005 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -374,6 +374,12 @@ public:
keys_map.clear_all();
bzero((char*) keys,sizeof(keys));
}
+ /*
+ Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
+ keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
+ merit in range analyzer functions (e.g. get_mm_parts) returning a
+ pointer to such SEL_TREE instead of NULL)
+ */
SEL_ARG *keys[MAX_KEY];
key_map keys_map; /* bitmask of non-NULL elements in keys */
@@ -822,6 +828,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
bool no_alloc, MEM_ROOT *parent_alloc)
:dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),range(0)
{
+ my_bitmap_map *bitmap;
+ DBUG_ENTER("QUICK_RANGE_SELECT::QUICK_RANGE_SELECT");
+
+ in_ror_merged_scan= 0;
sorted= 0;
index= key_nr;
head= table;
@@ -845,6 +855,19 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
bzero((char*) &alloc,sizeof(alloc));
file= head->file;
record= head->record[0];
+ save_read_set= head->read_set;
+ save_write_set= head->write_set;
+
+ /* Allocate a bitmap for used columns */
+ if (!(bitmap= (my_bitmap_map*) my_malloc(head->s->column_bitmap_size,
+ MYF(MY_WME))))
+ {
+ column_bitmap.bitmap= 0;
+ error= 1;
+ }
+ else
+ bitmap_init(&column_bitmap, bitmap, head->s->fields, FALSE);
+ DBUG_VOID_RETURN;
}
@@ -874,24 +897,26 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
if (file)
{
range_end();
- file->extra(HA_EXTRA_NO_KEYREAD);
if (free_file)
{
DBUG_PRINT("info", ("Freeing separate handler %p (free=%d)", file,
free_file));
- file->ha_reset();
file->ha_external_lock(current_thd, F_UNLCK);
file->close();
delete file;
}
+ else
+ {
+ file->extra(HA_EXTRA_NO_KEYREAD);
+ }
}
delete_dynamic(&ranges); /* ranges are allocated in alloc */
free_root(&alloc,MYF(0));
+ my_free((char*) column_bitmap.bitmap, MYF(MY_ALLOW_ZERO_PTR));
}
- if (multi_range)
- my_free((char*) multi_range, MYF(0));
- if (multi_range_buff)
- my_free((char*) multi_range_buff, MYF(0));
+ head->column_bitmaps_set(save_read_set, save_write_set);
+ x_free(multi_range);
+ x_free(multi_range_buff);
DBUG_VOID_RETURN;
}
@@ -1011,20 +1036,21 @@ int QUICK_ROR_INTERSECT_SELECT::init()
int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
{
- handler *save_file= file;
+ handler *save_file= file, *org_file;
THD *thd;
+ MY_BITMAP *bitmap;
DBUG_ENTER("QUICK_RANGE_SELECT::init_ror_merged_scan");
+ in_ror_merged_scan= 1;
if (reuse_handler)
{
- DBUG_PRINT("info", ("Reusing handler %p", file));
- if (file->extra(HA_EXTRA_KEYREAD) ||
- file->ha_retrieve_all_pk() ||
- init() || reset())
+ DBUG_PRINT("info", ("Reusing handler 0x%lx", (long) file));
+ if (init() || reset())
{
DBUG_RETURN(1);
}
- DBUG_RETURN(0);
+ head->column_bitmaps_set(&column_bitmap, &column_bitmap);
+ goto end;
}
/* Create a separate handler object for this quick select */
@@ -1037,19 +1063,20 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
thd= head->in_use;
if (!(file= get_new_handler(head->s, thd->mem_root, head->s->db_type)))
goto failure;
- DBUG_PRINT("info", ("Allocated new handler %p", file));
+ DBUG_PRINT("info", ("Allocated new handler 0x%lx", (long) file));
if (file->ha_open(head, head->s->normalized_path.str, head->db_stat,
HA_OPEN_IGNORE_IF_LOCKED))
{
/* Caller will free the memory */
goto failure;
}
+
+ head->column_bitmaps_set(&column_bitmap, &column_bitmap);
+
if (file->ha_external_lock(thd, F_RDLCK))
goto failure;
- if (file->extra(HA_EXTRA_KEYREAD) ||
- file->ha_retrieve_all_pk() ||
- init() || reset())
+ if (init() || reset())
{
file->ha_external_lock(thd, F_UNLCK);
file->close();
@@ -1057,11 +1084,28 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
}
free_file= TRUE;
last_rowid= file->ref;
+
+end:
+ /*
+ We are only going to read key fields and call position() on 'file'
+ The following sets head->tmp_set to only use this key and then updates
+ head->read_set and head->write_set to use this bitmap.
+ The now bitmap is stored in 'column_bitmap' which is used in ::get_next()
+ */
+ org_file= head->file;
+ head->file= file;
+ /* We don't have to set 'head->keyread' here as the 'file' is unique */
+ head->mark_columns_used_by_index(index);
+ head->prepare_for_position();
+ head->file= org_file;
+ bitmap_copy(&column_bitmap, head->read_set);
+ head->column_bitmaps_set(&column_bitmap, &column_bitmap);
+
DBUG_RETURN(0);
failure:
- if (file)
- delete file;
+ head->column_bitmaps_set(save_read_set, save_write_set);
+ delete file;
file= save_file;
DBUG_RETURN(1);
}
@@ -1766,32 +1810,26 @@ public:
static int fill_used_fields_bitmap(PARAM *param)
{
TABLE *table= param->table;
- param->fields_bitmap_size= bitmap_buffer_size(table->s->fields+1);
- uint32 *tmp;
+ my_bitmap_map *tmp;
uint pk;
- if (!(tmp= (uint32*) alloc_root(param->mem_root,param->fields_bitmap_size)) ||
- bitmap_init(&param->needed_fields, tmp, param->fields_bitmap_size*8,
- FALSE))
+ param->fields_bitmap_size= table->s->column_bitmap_size;
+ if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root,
+ param->fields_bitmap_size)) ||
+ bitmap_init(&param->needed_fields, tmp, table->s->fields, FALSE))
return 1;
- bitmap_clear_all(&param->needed_fields);
- for (uint i= 0; i < table->s->fields; i++)
- {
- if (param->thd->query_id == table->field[i]->query_id)
- bitmap_set_bit(&param->needed_fields, i+1);
- }
+ bitmap_copy(&param->needed_fields, table->read_set);
+ bitmap_union(&param->needed_fields, table->write_set);
pk= param->table->s->primary_key;
- if (param->table->file->primary_key_is_clustered() && pk != MAX_KEY)
+ if (pk != MAX_KEY && param->table->file->primary_key_is_clustered())
{
/* The table uses clustered PK and it is not internally generated */
KEY_PART_INFO *key_part= param->table->key_info[pk].key_part;
KEY_PART_INFO *key_part_end= key_part +
param->table->key_info[pk].key_parts;
for (;key_part != key_part_end; ++key_part)
- {
- bitmap_clear_bit(&param->needed_fields, key_part->fieldnr);
- }
+ bitmap_clear_bit(&param->needed_fields, key_part->fieldnr-1);
}
return 0;
}
@@ -1843,7 +1881,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
keys_to_use.to_ulonglong(), (ulong) prev_tables,
(ulong) const_tables));
- DBUG_PRINT("info", ("records=%lu", (ulong)head->file->records));
+ DBUG_PRINT("info", ("records: %lu", (ulong) head->file->stats.records));
delete quick;
quick=0;
needed_reg.clear_all();
@@ -1853,7 +1891,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_RETURN(0); /* purecov: inspected */
if (keys_to_use.is_clear_all())
DBUG_RETURN(0);
- records= head->file->records;
+ records= head->file->stats.records;
if (!records)
records++; /* purecov: inspected */
scan_time= (double) records / TIME_FOR_COMPARE + 1;
@@ -1878,7 +1916,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
/* set up parameter that is passed to all functions */
param.thd= thd;
- param.baseflag=head->file->table_flags();
+ param.baseflag=head->file->ha_table_flags();
param.prev_tables=prev_tables | const_tables;
param.read_tables=read_tables;
param.current_table= head->map;
@@ -2296,6 +2334,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
PART_PRUNE_PARAM prune_param;
MEM_ROOT alloc;
RANGE_OPT_PARAM *range_par= &prune_param.range_param;
+ my_bitmap_map *old_read_set, *old_write_set;
prune_param.part_info= part_info;
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
@@ -2309,6 +2348,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
DBUG_RETURN(FALSE);
}
+ old_write_set= dbug_tmp_use_all_columns(table, table->write_set);
+ old_read_set= dbug_tmp_use_all_columns(table, table->read_set);
range_par->thd= thd;
range_par->table= table;
/* range_par->cond doesn't need initialization */
@@ -2398,6 +2439,8 @@ all_used:
retval= FALSE; // some partitions are used
mark_all_partitions_as_used(prune_param.part_info);
end:
+ dbug_tmp_restore_column_map(table->write_set, old_write_set);
+ dbug_tmp_restore_column_map(table->read_set, old_read_set);
thd->no_errors=0;
thd->mem_root= range_par->old_root;
free_root(&alloc,MYF(0)); // Return memory & allocator
@@ -2424,6 +2467,8 @@ end:
void store_key_image_to_rec(Field *field, char *ptr, uint len)
{
/* Do the same as print_key() does */
+ my_bitmap_map *old_map;
+
if (field->real_maybe_null())
{
if (*ptr)
@@ -2434,7 +2479,10 @@ void store_key_image_to_rec(Field *field, char *ptr, uint len)
field->set_notnull();
ptr++;
}
+ old_map= dbug_tmp_use_all_columns(field->table,
+ field->table->write_set);
field->set_key_image(ptr, len);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
}
@@ -2514,11 +2562,11 @@ static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar,
{
MY_BITMAP all_merges;
uint bitmap_bytes;
- uint32 *bitmap_buf;
+ my_bitmap_map *bitmap_buf;
uint n_bits= ppar->part_info->used_partitions.n_bits;
bitmap_bytes= bitmap_buffer_size(n_bits);
- if (!(bitmap_buf= (uint32*)alloc_root(ppar->range_param.mem_root,
- bitmap_bytes)))
+ if (!(bitmap_buf= (my_bitmap_map*) alloc_root(ppar->range_param.mem_root,
+ bitmap_bytes)))
{
/*
Fallback, process just the first SEL_IMERGE. This can leave us with more
@@ -2580,7 +2628,8 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
ppar->cur_part_fields= 0;
ppar->cur_subpart_fields= 0;
init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
- if (-1 == (res |= find_used_partitions(ppar, (*ptree)->keys[0])))
+ SEL_ARG *key_tree= (*ptree)->keys[0];
+ if (!key_tree || (-1 == (res |= find_used_partitions(ppar, key_tree))))
return -1;
}
return res;
@@ -2764,7 +2813,8 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
uint32 subpart_id;
bitmap_clear_all(&ppar->subparts_bitmap);
- while ((subpart_id= subpart_iter.get_next(&subpart_iter)) != NOT_A_PARTITION_ID)
+ while ((subpart_id= subpart_iter.get_next(&subpart_iter)) !=
+ NOT_A_PARTITION_ID)
bitmap_set_bit(&ppar->subparts_bitmap, subpart_id);
/* Mark each partition as used in each subpartition. */
@@ -2870,7 +2920,8 @@ process_next_key_part:
/* Got "full range" for subpartitioning fields */
uint32 part_id;
bool found= FALSE;
- while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) != NOT_A_PARTITION_ID)
+ while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
+ NOT_A_PARTITION_ID)
{
ppar->mark_full_partition_used(ppar->part_info, part_id);
found= TRUE;
@@ -3017,11 +3068,12 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
if (ppar->subpart_fields)
{
- uint32 *buf;
+ my_bitmap_map *buf;
uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts);
- if (!(buf= (uint32*)alloc_root(alloc, bufsize)))
+ if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize)))
return TRUE;
- bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts, FALSE);
+ bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts,
+ FALSE);
}
range_par->key_parts= key_part;
Field **field= (ppar->part_fields)? part_info->part_field_array :
@@ -3188,7 +3240,8 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
else
{
double n_blocks=
- ceil(ulonglong2double(param->table->file->data_file_length) / IO_SIZE);
+ ceil(ulonglong2double(param->table->file->stats.data_file_length) /
+ IO_SIZE);
double busy_blocks=
n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, rows2double(records)));
if (busy_blocks < 1.0)
@@ -3357,7 +3410,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
DBUG_PRINT("info", ("index_merge scans cost=%g", imerge_cost));
if (imerge_too_expensive || (imerge_cost > read_time) ||
- (non_cpk_scan_records+cpk_scan_records >= param->table->file->records) &&
+ (non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) &&
read_time != DBL_MAX)
{
/*
@@ -3415,7 +3468,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
imerge_trp->read_cost= imerge_cost;
imerge_trp->records= non_cpk_scan_records + cpk_scan_records;
imerge_trp->records= min(imerge_trp->records,
- param->table->file->records);
+ param->table->file->stats.records);
imerge_trp->range_scans= range_scans;
imerge_trp->range_scans_end= range_scans + n_child_scans;
read_time= imerge_cost;
@@ -3476,7 +3529,7 @@ skip_to_ror_scan:
((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
roru_total_records += (*cur_roru_plan)->records;
roru_intersect_part *= (*cur_roru_plan)->records /
- param->table->file->records;
+ param->table->file->stats.records;
}
/*
@@ -3486,7 +3539,7 @@ skip_to_ror_scan:
in disjunction do not share key parts.
*/
roru_total_records -= (ha_rows)(roru_intersect_part*
- param->table->file->records);
+ param->table->file->stats.records);
/* ok, got a ROR read plan for each of the disjuncts
Calculate cost:
cost(index_union_scan(scan_1, ... scan_n)) =
@@ -3547,7 +3600,7 @@ static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr)
{
double read_time;
- uint keys_per_block= (param->table->file->block_size/2/
+ uint keys_per_block= (param->table->file->stats.block_size/2/
(param->table->key_info[keynr].key_length+
param->table->file->ref_length) + 1);
read_time=((double) (records+keys_per_block-1)/
@@ -3599,7 +3652,7 @@ static
ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
{
ROR_SCAN_INFO *ror_scan;
- uint32 *bitmap_buf;
+ my_bitmap_map *bitmap_buf;
uint keynr;
DBUG_ENTER("make_ror_scan");
@@ -3614,12 +3667,12 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
ror_scan->sel_arg= sel_arg;
ror_scan->records= param->table->quick_rows[keynr];
- if (!(bitmap_buf= (uint32*)alloc_root(param->mem_root,
- param->fields_bitmap_size)))
+ if (!(bitmap_buf= (my_bitmap_map*) alloc_root(param->mem_root,
+ param->fields_bitmap_size)))
DBUG_RETURN(NULL);
if (bitmap_init(&ror_scan->covered_fields, bitmap_buf,
- param->fields_bitmap_size*8, FALSE))
+ param->table->s->fields, FALSE))
DBUG_RETURN(NULL);
bitmap_clear_all(&ror_scan->covered_fields);
@@ -3628,8 +3681,8 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
param->table->key_info[keynr].key_parts;
for (;key_part != key_part_end; ++key_part)
{
- if (bitmap_is_set(&param->needed_fields, key_part->fieldnr))
- bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr);
+ if (bitmap_is_set(&param->needed_fields, key_part->fieldnr-1))
+ bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1);
}
ror_scan->index_read_cost=
get_index_only_read_time(param, param->table->quick_rows[ror_scan->keynr],
@@ -3729,21 +3782,21 @@ static
ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param)
{
ROR_INTERSECT_INFO *info;
- uint32* buf;
+ my_bitmap_map* buf;
if (!(info= (ROR_INTERSECT_INFO*)alloc_root(param->mem_root,
sizeof(ROR_INTERSECT_INFO))))
return NULL;
info->param= param;
- if (!(buf= (uint32*)alloc_root(param->mem_root,
- param->fields_bitmap_size)))
+ if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root,
+ param->fields_bitmap_size)))
return NULL;
- if (bitmap_init(&info->covered_fields, buf, param->fields_bitmap_size*8,
+ if (bitmap_init(&info->covered_fields, buf, param->table->s->fields,
FALSE))
return NULL;
info->is_covering= FALSE;
info->index_scan_costs= 0.0;
info->index_records= 0;
- info->out_rows= param->table->file->records;
+ info->out_rows= param->table->file->stats.records;
bitmap_clear_all(&info->covered_fields);
return info;
}
@@ -3862,14 +3915,14 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
SEL_ARG *sel_arg, *tuple_arg= NULL;
bool cur_covered;
bool prev_covered= test(bitmap_is_set(&info->covered_fields,
- key_part->fieldnr));
+ key_part->fieldnr-1));
key_range min_range;
key_range max_range;
min_range.key= (byte*) key_val;
min_range.flag= HA_READ_KEY_EXACT;
max_range.key= (byte*) key_val;
max_range.flag= HA_READ_AFTER_KEY;
- ha_rows prev_records= info->param->table->file->records;
+ ha_rows prev_records= info->param->table->file->stats.records;
DBUG_ENTER("ror_intersect_selectivity");
for (sel_arg= scan->sel_arg; sel_arg;
@@ -3877,7 +3930,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
{
DBUG_PRINT("info",("sel_arg step"));
cur_covered= test(bitmap_is_set(&info->covered_fields,
- key_part[sel_arg->part].fieldnr));
+ key_part[sel_arg->part].fieldnr-1));
if (cur_covered != prev_covered)
{
/* create (part1val, ..., part{n-1}val) tuple. */
@@ -4006,15 +4059,15 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
}
info->total_cost= info->index_scan_costs;
- DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
+ DBUG_PRINT("info", ("info->total_cost: %g", info->total_cost));
if (!info->is_covering)
{
info->total_cost +=
get_sweep_read_cost(info->param, double2rows(info->out_rows));
DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
}
- DBUG_PRINT("info", ("New out_rows= %g", info->out_rows));
- DBUG_PRINT("info", ("New cost= %g, %scovering", info->total_cost,
+ DBUG_PRINT("info", ("New out_rows: %g", info->out_rows));
+ DBUG_PRINT("info", ("New cost: %g, %scovering", info->total_cost,
info->is_covering?"" : "non-"));
DBUG_RETURN(TRUE);
}
@@ -4093,7 +4146,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
double min_cost= DBL_MAX;
DBUG_ENTER("get_best_ror_intersect");
- if ((tree->n_ror_scans < 2) || !param->table->file->records)
+ if ((tree->n_ror_scans < 2) || !param->table->file->stats.records)
DBUG_RETURN(NULL);
/*
@@ -4262,7 +4315,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
F=set of all fields to cover
S={}
- do {
+ do
+ {
Order I by (#covered fields in F desc,
#components asc,
number of first not covered component asc);
@@ -4280,7 +4334,6 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
ROR_SCAN_INFO **ror_scan_mark;
ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end;
DBUG_ENTER("get_best_covering_ror_intersect");
- uint nbits= param->fields_bitmap_size*8;
for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan)
(*scan)->key_components=
@@ -4294,9 +4347,9 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
/*I=set of all covering indexes */
ror_scan_mark= tree->ror_scans;
- uint32 int_buf[MAX_KEY/32+1];
+ my_bitmap_map int_buf[MAX_KEY/(sizeof(my_bitmap_map)*8)+1];
MY_BITMAP covered_fields;
- if (bitmap_init(&covered_fields, int_buf, nbits, FALSE))
+ if (bitmap_init(&covered_fields, int_buf, param->table->s->fields, FALSE))
DBUG_RETURN(0);
bitmap_clear_all(&covered_fields);
@@ -4545,7 +4598,8 @@ QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param,
if ((quick_intrsect=
new QUICK_ROR_INTERSECT_SELECT(param->thd, param->table,
- retrieve_full_rows? (!is_covering):FALSE,
+ (retrieve_full_rows? (!is_covering) :
+ FALSE),
parent_alloc)))
{
DBUG_EXECUTE("info", print_ror_scans_arr(param->table,
@@ -4698,17 +4752,46 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
if (inv)
{
- /*
- We get here for conditions like "t.keypart NOT IN (....)".
-
- If the IN-list contains only constants (and func->array is an ordered
- array of them), we construct the appropriate SEL_ARG tree manually,
- because constructing it using the range analyzer (as
- AND_i( t.keypart != c_i)) will cause lots of memory to be consumed
- (see BUG#15872).
- */
if (func->array && func->cmp_type != ROW_RESULT)
{
+ /*
+ We get here for conditions in form "t.key NOT IN (c1, c2, ...)"
+ (where c{i} are constants).
+ Our goal is to produce a SEL_ARG graph that represents intervals:
+
+ ($MIN<t.key<c1) OR (c1<t.key<c2) OR (c2<t.key<c3) OR ... (*)
+
+ where $MIN is either "-inf" or NULL.
+
+ The most straightforward way to handle NOT IN would be to convert
+ it to "(t.key != c1) AND (t.key != c2) AND ..." and let the range
+ optimizer to build SEL_ARG graph from that. However that will cause
+ the range optimizer to use O(N^2) memory (it's a bug, not filed),
+ and people do use big NOT IN lists (see BUG#15872). Also, for big
+ NOT IN lists constructing/using graph (*) does not make the query
+ faster.
+
+ So, we will handle NOT IN manually in the following way:
+ * if the number of entries in the NOT IN list is less then
+ NOT_IN_IGNORE_THRESHOLD, we will construct SEL_ARG graph (*)
+ manually.
+ * Otherwise, we will construct a smaller graph: for
+ "t.key NOT IN (c1,...cN)" we construct a graph representing
+ ($MIN < t.key) OR (cN < t.key) // here sequence of c_i is
+ // ordered.
+
+ A note about partially-covering indexes: for those (e.g. for
+ "a CHAR(10), KEY(a(5))") the handling is correct (albeit not very
+ efficient):
+ Instead of "t.key < c1" we get "t.key <= prefix-val(c1)".
+ Combining the intervals in (*) together, we get:
+ (-inf<=t.key<=c1) OR (c1<=t.key<=c2) OR (c2<=t.key<=c3) OR ...
+ i.e. actually we get intervals combined into one interval:
+ (-inf<=t.key<=+inf). This doesn't make much sense but it doesn't
+ cause any problems.
+ */
+ MEM_ROOT *tmp_root= param->mem_root;
+ param->thd->mem_root= param->old_root;
/*
Create one Item_type constant object. We'll need it as
get_mm_parts only accepts constant values wrapped in Item_Type
@@ -4717,25 +4800,35 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
per-statement mem_root (while thd->mem_root is currently pointing
to mem_root local to range optimizer).
*/
- MEM_ROOT *tmp_root= param->mem_root;
- param->thd->mem_root= param->old_root;
Item *value_item= func->array->create_item();
param->thd->mem_root= tmp_root;
if (!value_item)
break;
- /* Get a SEL_TREE for "-inf < X < c_0" interval */
- func->array->value_to_item(0, value_item);
- tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
- value_item, cmp_type);
- if (!tree)
+ /* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
+ uint i=0;
+ do
+ {
+ func->array->value_to_item(i, value_item);
+ tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ value_item, cmp_type);
+ if (!tree)
+ break;
+ i++;
+ } while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE);
+
+ if (!tree || tree->type == SEL_TREE::IMPOSSIBLE)
+ {
+ /* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
+ tree= NULL;
break;
+ }
#define NOT_IN_IGNORE_THRESHOLD 1000
SEL_TREE *tree2;
if (func->array->count < NOT_IN_IGNORE_THRESHOLD)
{
- for (uint i=1; i < func->array->count; i++)
+ for (; i < func->array->count; i++)
{
if (func->array->compare_elems(i, i-1))
{
@@ -4743,32 +4836,44 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
func->array->value_to_item(i, value_item);
tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
value_item, cmp_type);
-
+ if (!tree2)
+ {
+ tree= NULL;
+ break;
+ }
+
/* Change all intervals to be "c_{i-1} < X < c_i" */
for (uint idx= 0; idx < param->keys; idx++)
{
- SEL_ARG *new_interval;
- if ((new_interval= tree2->keys[idx]))
+ SEL_ARG *new_interval, *last_val;
+ if (((new_interval= tree2->keys[idx])) &&
+ ((last_val= tree->keys[idx]->last())))
{
- SEL_ARG *last_val= tree->keys[idx]->last();
new_interval->min_value= last_val->max_value;
new_interval->min_flag= NEAR_MIN;
}
}
+ /*
+ The following doesn't try to allocate memory so no need to
+ check for NULL.
+ */
tree= tree_or(param, tree, tree2);
}
}
}
else
func->array->value_to_item(func->array->count - 1, value_item);
-
- /*
- Get the SEL_TREE for the last "c_last < X < +inf" interval
- (value_item cotains c_last already)
- */
- tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
- value_item, cmp_type);
- tree= tree_or(param, tree, tree2);
+
+ if (tree && tree->type != SEL_TREE::IMPOSSIBLE)
+ {
+ /*
+ Get the SEL_TREE for the last "c_last < X < +inf" interval
+ (value_item cotains c_last already)
+ */
+ tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
+ value_item, cmp_type);
+ tree= tree_or(param, tree, tree2);
+ }
}
else
{
@@ -5053,7 +5158,7 @@ get_mm_parts(RANGE_OPT_PARAM *param, COND *cond_func, Field *field,
tree->keys_map.set_bit(key_part->key);
}
}
-
+
DBUG_RETURN(tree);
}
@@ -7167,7 +7272,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
goto err;
quick->records= records;
- if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error ||
+ if (cp_buffer_from_ref(thd, table, ref) && thd->is_fatal_error ||
!(range= new(alloc) QUICK_RANGE()))
goto err; // out of memory
@@ -7230,10 +7335,9 @@ err:
rowids into Unique, get the sorted sequence and destroy the Unique.
If table has a clustered primary key that covers all rows (TRUE for bdb
- and innodb currently) and one of the index_merge scans is a scan on PK,
- then
- rows that will be retrieved by PK scan are not put into Unique and
- primary key scan is not performed here, it is performed later separately.
+ and innodb currently) and one of the index_merge scans is a scan on PK,
+ then rows that will be retrieved by PK scan are not put into Unique and
+ primary key scan is not performed here, it is performed later separately.
RETURN
0 OK
@@ -7246,21 +7350,17 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
QUICK_RANGE_SELECT* cur_quick;
int result;
Unique *unique;
- DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
+ MY_BITMAP *save_read_set, *save_write_set;
+ handler *file= head->file;
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge");
/* We're going to just read rowids. */
- if (head->file->extra(HA_EXTRA_KEYREAD))
- DBUG_RETURN(1);
-
- /*
- Make innodb retrieve all PK member fields, so
- * ha_innobase::position (which uses them) call works.
- * We can filter out rows that will be retrieved by clustered PK.
- (This also creates a deficiency - it is possible that we will retrieve
- parts of key that are not used by current query at all.)
- */
- if (head->file->ha_retrieve_all_pk())
- DBUG_RETURN(1);
+ save_read_set= head->read_set;
+ save_write_set= head->write_set;
+ file->extra(HA_EXTRA_KEYREAD);
+ bitmap_clear_all(&head->tmp_set);
+ head->column_bitmaps_set(&head->tmp_set, &head->tmp_set);
+ head->prepare_for_position();
cur_quick_it.rewind();
cur_quick= cur_quick_it++;
@@ -7273,8 +7373,8 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
if (cur_quick->init() || cur_quick->reset())
DBUG_RETURN(1);
- unique= new Unique(refpos_order_cmp, (void *)head->file,
- head->file->ref_length,
+ unique= new Unique(refpos_order_cmp, (void *)file,
+ file->ref_length,
thd->variables.sortbuff_size);
if (!unique)
DBUG_RETURN(1);
@@ -7317,15 +7417,16 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
}
+ DBUG_PRINT("info", ("ok"));
/* ok, all row ids are in Unique */
result= unique->get(head);
delete unique;
doing_pk_scan= FALSE;
+ /* index_merge currently doesn't support "using index" at all */
+ file->extra(HA_EXTRA_NO_KEYREAD);
+ head->column_bitmaps_set(save_read_set, save_write_set);
/* start table scan */
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
- /* index_merge currently doesn't support "using index" at all */
- head->file->extra(HA_EXTRA_NO_KEYREAD);
-
DBUG_RETURN(result);
}
@@ -7347,9 +7448,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
if (doing_pk_scan)
DBUG_RETURN(pk_quick_select->get_next());
- result= read_record.read_record(&read_record);
-
- if (result == -1)
+ if ((result= read_record.read_record(&read_record)) == -1)
{
result= HA_ERR_END_OF_FILE;
end_read_record(&read_record);
@@ -7357,7 +7456,8 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
if (pk_quick_select)
{
doing_pk_scan= TRUE;
- if ((result= pk_quick_select->init()) || (result= pk_quick_select->reset()))
+ if ((result= pk_quick_select->init()) ||
+ (result= pk_quick_select->reset()))
DBUG_RETURN(result);
DBUG_RETURN(pk_quick_select->get_next());
}
@@ -7399,16 +7499,12 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
{
/* Get a rowid for first quick and save it as a 'candidate' */
quick= quick_it++;
+ error= quick->get_next();
if (cpk_quick)
{
- do
- {
+ while (!error && !cpk_quick->row_in_ranges())
error= quick->get_next();
- }while (!error && !cpk_quick->row_in_ranges());
}
- else
- error= quick->get_next();
-
if (error)
DBUG_RETURN(error);
@@ -7454,7 +7550,7 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
}
}
- /* We get here iff we got the same row ref in all scans. */
+ /* We get here if we got the same row ref in all scans. */
if (need_to_fetch_row)
error= head->file->rnd_pos(head->record[0], last_rowid);
} while (error == HA_ERR_RECORD_DELETED);
@@ -7527,6 +7623,7 @@ int QUICK_ROR_UNION_SELECT::get_next()
DBUG_RETURN(error);
}
+
int QUICK_RANGE_SELECT::reset()
{
uint mrange_bufsiz;
@@ -7566,7 +7663,7 @@ int QUICK_RANGE_SELECT::reset()
}
/* Allocate the handler buffer if necessary. */
- if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
+ if (file->ha_table_flags() & HA_NEED_READ_RANGE_BUFFER)
{
mrange_bufsiz= min(multi_range_bufsiz,
(QUICK_SELECT_I::records + 1)* head->s->reclength);
@@ -7631,6 +7728,15 @@ int QUICK_RANGE_SELECT::get_next()
(cur_range >= (QUICK_RANGE**) ranges.buffer) &&
(cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements));
+ if (in_ror_merged_scan)
+ {
+ /*
+ We don't need to signal the bitmap change as the bitmap is always the
+ same for this head->file
+ */
+ head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap);
+ }
+
for (;;)
{
if (in_range)
@@ -7638,10 +7744,7 @@ int QUICK_RANGE_SELECT::get_next()
/* We did already start to read this key. */
result= file->read_multi_range_next(&mrange);
if (result != HA_ERR_END_OF_FILE)
- {
- in_range= ! result;
- DBUG_RETURN(result);
- }
+ goto end;
}
uint count= min(multi_range_length, ranges.elements -
@@ -7650,6 +7753,8 @@ int QUICK_RANGE_SELECT::get_next()
{
/* Ranges have already been used up before. None is left for read. */
in_range= FALSE;
+ if (in_ror_merged_scan)
+ head->column_bitmaps_set_no_signal(save_read_set, save_write_set);
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
KEY_MULTI_RANGE *mrange_slot, *mrange_end;
@@ -7681,12 +7786,18 @@ int QUICK_RANGE_SELECT::get_next()
result= file->read_multi_range_first(&mrange, multi_range, count,
sorted, multi_range_buff);
if (result != HA_ERR_END_OF_FILE)
- {
- in_range= ! result;
- DBUG_RETURN(result);
- }
+ goto end;
in_range= FALSE; /* No matching rows; go to next set of ranges. */
}
+
+end:
+ in_range= ! result;
+ if (in_ror_merged_scan)
+ {
+ /* Restore bitmaps set on entry */
+ head->column_bitmaps_set_no_signal(save_read_set, save_write_set);
+ }
+ DBUG_RETURN(result);
}
@@ -7863,7 +7974,7 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
uint used_key_parts)
- : QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
+ :QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
{
QUICK_RANGE *r;
@@ -8339,9 +8450,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
groups, and thus can be applied after the grouping.
GA4. There are no expressions among G_i, just direct column references.
NGA1.If in the index I there is a gap between the last GROUP attribute G_k,
- and the MIN/MAX attribute C, then NGA must consist of exactly the index
- attributes that constitute the gap. As a result there is a permutation
- of NGA that coincides with the gap in the index <B_1, ..., B_m>.
+ and the MIN/MAX attribute C, then NGA must consist of exactly the
+ index attributes that constitute the gap. As a result there is a
+ permutation of NGA that coincides with the gap in the index
+ <B_1, ..., B_m>.
NGA2.If BA <> {}, then the WHERE clause must contain a conjunction EQ of
equality conditions for all NG_i of the form (NG_i = const) or
(const = NG_i), such that each NG_i is referenced in exactly one
@@ -8349,9 +8461,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
gap in the index.
WA1. There are no other attributes in the WHERE clause except the ones
referenced in predicates RNG, PA, PC, EQ defined above. Therefore
- WA is subset of (GA union NGA union C) for GA,NGA,C that pass the above
- tests. By transitivity then it also follows that each WA_i participates
- in the index I (if this was already tested for GA, NGA and C).
+ WA is subset of (GA union NGA union C) for GA,NGA,C that pass the
+ above tests. By transitivity then it also follows that each WA_i
+ participates in the index I (if this was already tested for GA, NGA
+ and C).
C) Overall query form:
SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
@@ -8413,12 +8526,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
TABLE *table= param->table;
bool have_min= FALSE; /* TRUE if there is a MIN function. */
bool have_max= FALSE; /* TRUE if there is a MAX function. */
- Item_field *min_max_arg_item= NULL;/* The argument of all MIN/MAX functions.*/
+ Item_field *min_max_arg_item= NULL; // The argument of all MIN/MAX functions
KEY_PART_INFO *min_max_arg_part= NULL; /* The corresponding keypart. */
uint group_prefix_len= 0; /* Length (in bytes) of the key prefix. */
KEY *index_info= NULL; /* The index chosen for data access. */
uint index= 0; /* The id of the chosen index. */
- uint group_key_parts= 0; /* Number of index key parts in the group prefix. */
+ uint group_key_parts= 0; // Number of index key parts in the group prefix.
uint used_key_parts= 0; /* Number of index key parts used for access. */
byte key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/
uint key_infix_len= 0; /* Length of key_infix. */
@@ -8536,28 +8649,19 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
we check that all query fields are indeed covered by 'cur_index'.
*/
if (pk < MAX_KEY && cur_index != pk &&
- (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
+ (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
{
/* For each table field */
for (uint i= 0; i < table->s->fields; i++)
{
Field *cur_field= table->field[i];
/*
- If the field is used in the current query, check that the
- field is covered by some keypart of the current index.
+ If the field is used in the current query ensure that it's
+ part of 'cur_index'
*/
- if (thd->query_id == cur_field->query_id)
- {
- KEY_PART_INFO *key_part= cur_index_info->key_part;
- KEY_PART_INFO *key_part_end= key_part + cur_index_info->key_parts;
- for (;;)
- {
- if (key_part->field == cur_field)
- break;
- if (++key_part == key_part_end)
- goto next_index; // Field was not part of key
- }
- }
+ if (bitmap_is_set(table->read_set, cur_field->field_index) &&
+ !cur_field->part_of_key_not_clustered.is_set(cur_index))
+ goto next_index; // Field was not part of key
}
}
@@ -8711,7 +8815,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
key_part_range[1]= last_part;
/* Check if cur_part is referenced in the WHERE clause. */
- if (join->conds->walk(&Item::find_item_in_field_list_processor,
+ if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
(byte*) key_part_range))
goto next_index;
}
@@ -8725,7 +8829,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
{
for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++)
{
- if (cur_part->field->query_id == thd->query_id)
+ if (bitmap_is_set(table->read_set, cur_part->field->field_index))
goto next_index;
}
}
@@ -9189,8 +9293,8 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */
DBUG_ENTER("cost_group_min_max");
- table_records= table->file->records;
- keys_per_block= (table->file->block_size / 2 /
+ table_records= table->file->stats.records;
+ keys_per_block= (table->file->stats.block_size / 2 /
(index_info->key_length + table->file->ref_length)
+ 1);
num_blocks= (table_records / keys_per_block) + 1;
@@ -10363,6 +10467,10 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
const char *key_end= key+used_length;
String tmp(buff,sizeof(buff),&my_charset_bin);
uint store_length;
+ TABLE *table= key_part->field->table;
+ my_bitmap_map *old_write_set, *old_read_set;
+ old_write_set= dbug_tmp_use_all_columns(table, table->write_set);
+ old_read_set= dbug_tmp_use_all_columns(table, table->read_set);
for (; key < key_end; key+=store_length, key_part++)
{
@@ -10388,18 +10496,28 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
if (key+store_length < key_end)
fputc('/',DBUG_FILE);
}
+ dbug_tmp_restore_column_map(table->write_set, old_write_set);
+ dbug_tmp_restore_column_map(table->read_set, old_read_set);
}
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
{
char buf[MAX_KEY/8+1];
+ TABLE *table;
+ my_bitmap_map *old_read_map, *old_write_map;
DBUG_ENTER("print_quick");
if (!quick)
DBUG_VOID_RETURN;
DBUG_LOCK_FILE;
+ table= quick->head;
+ old_read_map= dbug_tmp_use_all_columns(table, table->read_set);
+ old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
quick->dbug_dump(0, TRUE);
+ dbug_tmp_restore_column_map(table->read_set, old_read_map);
+ dbug_tmp_restore_column_map(table->write_set, old_write_map);
+
fprintf(DBUG_FILE,"other_keys: 0x%s:\n", needed_reg->print(buf));
DBUG_UNLOCK_FILE;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index bc2496b0769..85cedf663cd 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -192,8 +192,9 @@ public:
function is called.
SYNOPSIS
init_ror_merged_scan()
- reuse_handler If true, the quick select may use table->handler, otherwise
- it must create and use a separate handler object.
+ reuse_handler If true, the quick select may use table->handler,
+ otherwise it must create and use a separate handler
+ object.
RETURN
0 Ok
other Error
@@ -259,7 +260,7 @@ class SEL_ARG;
class QUICK_RANGE_SELECT : public QUICK_SELECT_I
{
protected:
- bool next,dont_free;
+ bool next,dont_free,in_ror_merged_scan;
public:
int error;
protected:
@@ -277,8 +278,8 @@ protected:
freed by QUICK_RANGE_SELECT) */
HANDLER_BUFFER *multi_range_buff; /* the handler buffer (allocated and
freed by QUICK_RANGE_SELECT) */
+ MY_BITMAP column_bitmap, *save_read_set, *save_write_set;
-protected:
friend class TRP_ROR_INTERSECT;
friend
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index d4e7745551a..ce3f5c5f108 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -55,6 +55,36 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
/*
+ Get exact count of rows in all tables
+
+ SYNOPSIS
+ get_exact_records()
+ tables List of tables
+
+ NOTES
+ When this is called, we know all table handlers supports HA_HAS_RECORDS
+ or HA_STATS_RECORDS_IS_EXACT
+
+ RETURN
+ ULONGLONG_MAX Error: Could not calculate number of rows
+ # Multiplication of number of rows in all tables
+*/
+
+static ulonglong get_exact_record_count(TABLE_LIST *tables)
+{
+ ulonglong count= 1;
+ for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
+ {
+ ha_rows tmp= tl->table->file->records();
+ if ((tmp == HA_POS_ERROR))
+ return ULONGLONG_MAX;
+ count*= tmp;
+ }
+ return count;
+}
+
+
+/*
Substitutes constants for some COUNT(), MIN() and MAX() functions.
SYNOPSIS
@@ -80,8 +110,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
List_iterator_fast<Item> it(all_fields);
int const_result= 1;
bool recalc_const_item= 0;
- longlong count= 1;
- bool is_exact_count= TRUE;
+ ulonglong count= 1;
+ bool is_exact_count= TRUE, maybe_exact_count= TRUE;
table_map removed_tables= 0, outer_tables= 0, used_tables= 0;
table_map where_tables= 0;
Item *item;
@@ -120,22 +150,25 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
used_tables|= tl->table->map;
/*
- If the storage manager of 'tl' gives exact row count, compute the total
- number of rows. If there are no outer table dependencies, this count
- may be used as the real count.
+ If the storage manager of 'tl' gives exact row count as part of
+ statistics (cheap), compute the total number of rows. If there are
+ no outer table dependencies, this count may be used as the real count.
Schema tables are filled after this function is invoked, so we can't
get row count
*/
- if ((tl->table->file->table_flags() & HA_NOT_EXACT_COUNT) ||
+ if (!(tl->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) ||
tl->schema_table)
{
+ maybe_exact_count&= test(!tl->schema_table &&
+ (tl->table->file->ha_table_flags() &
+ HA_HAS_RECORDS));
is_exact_count= FALSE;
count= 1; // ensure count != 0
}
else
{
tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- count*= tl->table->file->records;
+ count*= tl->table->file->stats.records;
}
}
@@ -157,9 +190,19 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
there are no outer joins.
*/
if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null &&
- !outer_tables && is_exact_count)
+ !outer_tables && maybe_exact_count)
{
- ((Item_sum_count*) item)->make_const(count);
+ if (!is_exact_count)
+ {
+ if ((count= get_exact_record_count(tables)) == ULONGLONG_MAX)
+ {
+ /* Error from handler in counting rows. Don't optimize count() */
+ const_result= 0;
+ continue;
+ }
+ is_exact_count= 1; // count is now exact
+ }
+ ((Item_sum_count*) item)->make_const((longlong) count);
recalc_const_item= 1;
}
else
diff --git a/sql/partition_element.h b/sql/partition_element.h
index 13693934c0f..90d0bda87c1 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -64,8 +64,20 @@ public:
engine_type(NULL),part_state(PART_NORMAL),
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE)
{
- subpartitions.empty();
- list_val_list.empty();
+ }
+ partition_element(partition_element *part_elem)
+ : part_max_rows(part_elem->part_max_rows),
+ part_min_rows(part_elem->part_min_rows),
+ partition_name(NULL),
+ tablespace_name(part_elem->tablespace_name),
+ range_value(0), part_comment(part_elem->part_comment),
+ data_file_name(part_elem->data_file_name),
+ index_file_name(part_elem->index_file_name),
+ engine_type(part_elem->engine_type),
+ part_state(part_elem->part_state),
+ nodegroup_id(part_elem->nodegroup_id),
+ has_null_value(FALSE)
+ {
}
~partition_element() {}
};
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 6761b28331e..edd8f56d8c4 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -267,7 +267,7 @@ bool partition_info::set_up_default_subpartitions(handler *file,
j= 0;
do
{
- partition_element *subpart_elem= new partition_element();
+ partition_element *subpart_elem= new partition_element(part_elem);
if (likely(subpart_elem != 0 &&
(!part_elem->subpartitions.push_back(subpart_elem))))
{
@@ -432,18 +432,22 @@ char *partition_info::has_unique_names()
bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts)
{
uint i= 0;
- bool result= FALSE;
DBUG_ENTER("partition_info::check_engine_mix");
do
{
if (engine_array[i] != engine_array[0])
{
- result= TRUE;
- break;
+ my_error(ER_MIX_HANDLER_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
}
} while (++i < no_parts);
- DBUG_RETURN(result);
+ if (engine_array[0] == &myisammrg_hton)
+ {
+ my_error(ER_PARTITION_MERGE_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
}
@@ -631,8 +635,8 @@ bool partition_info::check_list_constants()
&list_part_cmp);
not_first= FALSE;
- i= prev_value= 0; //prev_value initialised to quiet compiler
- do
+ prev_value= 0; // prev_value initialised to quiet compiler
+ for (i= 0; i < no_list_values ; i++)
{
curr_value= list_array[i].list_value;
if (likely(!not_first || prev_value != curr_value))
@@ -645,7 +649,7 @@ bool partition_info::check_list_constants()
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
- } while (++i < no_list_values);
+ }
result= FALSE;
end:
DBUG_RETURN(result);
@@ -681,8 +685,20 @@ bool partition_info::check_partition_info(handlerton **eng_type,
uint i, tot_partitions;
bool result= TRUE;
char *same_name;
+ bool part_expression_ok= TRUE;
DBUG_ENTER("partition_info::check_partition_info");
+ if (part_type != HASH_PARTITION || !list_of_part_fields)
+ part_expr->walk(&Item::check_partition_func_processor, 0,
+ (byte*)(&part_expression_ok));
+ if (is_sub_partitioned() && !list_of_subpart_fields)
+ subpart_expr->walk(&Item::check_partition_func_processor, 0,
+ (byte*)(&part_expression_ok));
+ if (!part_expression_ok)
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ goto end;
+ }
if (unlikely(!is_sub_partitioned() &&
!(use_default_subpartitions && use_default_no_subpartitions)))
{
@@ -720,6 +736,8 @@ bool partition_info::check_partition_info(handlerton **eng_type,
do
{
partition_element *part_elem= part_it++;
+ if (part_elem->engine_type == NULL)
+ part_elem->engine_type= default_engine_type;
if (!is_sub_partitioned())
{
if (check_table_name(part_elem->partition_name,
@@ -728,8 +746,6 @@ bool partition_info::check_partition_info(handlerton **eng_type,
my_error(ER_WRONG_PARTITION_NAME, MYF(0));
goto end;
}
- if (part_elem->engine_type == NULL)
- part_elem->engine_type= default_engine_type;
DBUG_PRINT("info", ("engine = %d",
ha_legacy_type(part_elem->engine_type)));
engine_array[part_count++]= part_elem->engine_type;
@@ -740,27 +756,24 @@ bool partition_info::check_partition_info(handlerton **eng_type,
List_iterator<partition_element> sub_it(part_elem->subpartitions);
do
{
- part_elem= sub_it++;
- if (check_table_name(part_elem->partition_name,
- strlen(part_elem->partition_name)))
+ partition_element *sub_elem= sub_it++;
+ if (check_table_name(sub_elem->partition_name,
+ strlen(sub_elem->partition_name)))
{
my_error(ER_WRONG_PARTITION_NAME, MYF(0));
goto end;
}
- if (part_elem->engine_type == NULL)
- part_elem->engine_type= default_engine_type;
+ if (sub_elem->engine_type == NULL)
+ sub_elem->engine_type= default_engine_type;
DBUG_PRINT("info", ("engine = %u",
- ha_legacy_type(part_elem->engine_type)));
- engine_array[part_count++]= part_elem->engine_type;
+ ha_legacy_type(sub_elem->engine_type)));
+ engine_array[part_count++]= sub_elem->engine_type;
} while (++j < no_subparts);
}
} while (++i < no_parts);
}
if (unlikely(partition_info::check_engine_mix(engine_array, part_count)))
- {
- my_error(ER_MIX_HANDLER_ERROR, MYF(0));
goto end;
- }
if (eng_type)
*eng_type= (handlerton*)engine_array[0];
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 650bd8fc58f..bb0891cdbbe 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -924,8 +924,19 @@ bool Protocol_simple::store(Field *field)
char buff[MAX_FIELD_WIDTH];
String str(buff,sizeof(buff), &my_charset_bin);
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
+ TABLE *table= field->table;
+#ifdef DBUG_OFF
+ my_bitmap_map *old_map= 0;
+ if (table->file)
+ old_map= dbug_tmp_use_all_columns(table, table->read_set);
+#endif
field->val_str(&str);
+#ifdef DBUG_OFF
+ if (old_map)
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+#endif
+
return store_string_aux(str.ptr(), str.length(), str.charset(), tocs);
}
diff --git a/sql/records.cc b/sql/records.cc
index 5cb9b1e5c47..b2505600b22 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -64,10 +64,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
table->status=0; /* And it's always found */
if (!table->file->inited)
- {
table->file->ha_index_init(idx, 1);
- table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
- }
/* read_record will be changed to rr_index in rr_index_first */
info->read_record= rr_index_first;
}
@@ -195,11 +192,11 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (!table->sort.addon_field &&
! (specialflag & SPECIAL_SAFE_MODE) &&
thd->variables.read_rnd_buff_size &&
- !(table->file->table_flags() & HA_FAST_KEY_READ) &&
+ !(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
(table->db_stat & HA_READ_ONLY ||
table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
- (ulonglong) table->s->reclength* (table->file->records+
- table->file->deleted) >
+ (ulonglong) table->s->reclength* (table->file->stats.records+
+ table->file->stats.deleted) >
(ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
info->io_cache->end_of_file/info->ref_length * table->s->reclength >
(my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
@@ -239,7 +236,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
(use_record_cache < 0 &&
- !(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE))))
+ !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
VOID(table->file->extra_opt(HA_EXTRA_CACHE,
thd->variables.read_buff_size));
}
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 9cabe1a3df0..66e2aa1c31c 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -61,12 +61,13 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
static int init_failsafe_rpl_thread(THD* thd)
{
DBUG_ENTER("init_failsafe_rpl_thread");
+ thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
/*
thd->bootstrap is to report errors barely to stderr; if this code is
enable again one day, one should check if bootstrap is still needed (maybe
this thread has no other error reporting method).
*/
- thd->system_thread = thd->bootstrap = 1;
+ thd->bootstrap = 1;
thd->security_ctx->skip_grants();
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 588c686e265..53b4b395c37 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -56,6 +56,8 @@
#include <thr_alarm.h>
#include <myisam.h>
+#include "event_scheduler.h"
+
/* WITH_BERKELEY_STORAGE_ENGINE */
extern bool berkeley_shared_data;
extern ulong berkeley_max_lock, berkeley_log_buffer_size;
@@ -106,7 +108,6 @@ extern ulong ndb_report_thresh_binlog_mem_usage;
-extern my_bool event_executor_running_global_var;
static HASH system_variable_hash;
const char *bool_type_names[]= { "OFF", "ON", NullS };
@@ -162,6 +163,7 @@ void fix_sql_mode_var(THD *thd, enum_var_type type);
static byte *get_error_count(THD *thd);
static byte *get_warning_count(THD *thd);
static byte *get_prepared_stmt_count(THD *thd);
+static byte *get_tmpdir(THD *thd);
/*
Variable definition list
@@ -184,6 +186,7 @@ sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset",
sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges",
&sp_automatic_privileges);
+sys_var_const_str sys_basedir("basedir", mysql_home);
sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
&binlog_cache_size);
sys_var_thd_binlog_format sys_binlog_format("binlog_format",
@@ -209,6 +212,7 @@ sys_var_long_ptr sys_concurrent_insert("concurrent_insert",
&myisam_concurrent_insert);
sys_var_long_ptr sys_connect_timeout("connect_timeout",
&connect_timeout);
+sys_var_const_str sys_datadir("datadir", mysql_real_data_home);
#ifndef DBUG_OFF
sys_var_thd_dbug sys_dbug("debug");
#endif
@@ -222,9 +226,8 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
&delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
&delayed_queue_size);
-sys_var_event_executor sys_event_executor("event_scheduler",
- (my_bool *)
- &event_executor_running_global_var);
+
+sys_var_event_scheduler sys_event_scheduler("event_scheduler");
sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
&expire_logs_days);
sys_var_bool_ptr sys_flush("flush", &myisam_flush);
@@ -262,6 +265,9 @@ sys_trust_routine_creators("log_bin_trust_routine_creators",
sys_var_bool_ptr
sys_trust_function_creators("log_bin_trust_function_creators",
&trust_function_creators);
+sys_var_bool_ptr
+ sys_log_queries_not_using_indexes("log_queries_not_using_indexes",
+ &opt_log_queries_not_using_indexes);
sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings);
sys_var_thd_ulong sys_long_query_time("long_query_time",
&SV::long_query_time);
@@ -389,6 +395,7 @@ sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size",
sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size",
&SV::query_prealloc_size,
0, fix_thd_mem_root);
+sys_var_readonly sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size",
&SV::trans_alloc_block_size,
0, fix_trans_mem_root);
@@ -425,6 +432,21 @@ sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
&SV::sortbuff_size);
sys_var_thd_sql_mode sys_sql_mode("sql_mode",
&SV::sql_mode);
+#ifdef HAVE_OPENSSL
+extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
+ *opt_ssl_key;
+sys_var_const_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca);
+sys_var_const_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath);
+sys_var_const_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert);
+sys_var_const_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher);
+sys_var_const_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key);
+#else
+sys_var_const_str sys_ssl_ca("ssl_ca", NULL);
+sys_var_const_str sys_ssl_capath("ssl_capath", NULL);
+sys_var_const_str sys_ssl_cert("ssl_cert", NULL);
+sys_var_const_str sys_ssl_cipher("ssl_cipher", NULL);
+sys_var_const_str sys_ssl_key("ssl_key", NULL);
+#endif
sys_var_thd_enum
sys_updatable_views_with_limit("updatable_views_with_limit",
&SV::updatable_views_with_limit,
@@ -696,7 +718,6 @@ static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff)
}
#endif /* HAVE_REPLICATION */
-
/*
Variables shown by SHOW variables in alphabetical order
*/
@@ -706,7 +727,7 @@ SHOW_VAR init_vars[]= {
{"auto_increment_offset", (char*) &sys_auto_increment_offset, SHOW_SYS},
{sys_automatic_sp_privileges.name,(char*) &sys_automatic_sp_privileges, SHOW_SYS},
{"back_log", (char*) &back_log, SHOW_LONG},
- {"basedir", mysql_home, SHOW_CHAR},
+ {sys_basedir.name, (char*) &sys_basedir, SHOW_SYS},
{"bdb_cache_parts", (char*) &berkeley_cache_parts, SHOW_LONG},
{"bdb_cache_size", (char*) &berkeley_cache_size, SHOW_LONGLONG},
{"bdb_home", (char*) &berkeley_home, SHOW_CHAR_PTR},
@@ -733,7 +754,7 @@ SHOW_VAR init_vars[]= {
{sys_completion_type.name, (char*) &sys_completion_type, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
- {"datadir", mysql_real_data_home, SHOW_CHAR},
+ {sys_datadir.name, (char*) &sys_datadir, SHOW_SYS},
{sys_date_format.name, (char*) &sys_date_format, SHOW_SYS},
{sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS},
#ifndef DBUG_OFF
@@ -747,7 +768,7 @@ SHOW_VAR init_vars[]= {
{sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
{sys_engine_condition_pushdown.name,
(char*) &sys_engine_condition_pushdown, SHOW_SYS},
- {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS},
+ {sys_event_scheduler.name, (char*) &sys_event_scheduler, SHOW_SYS},
{sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
{sys_flush.name, (char*) &sys_flush, SHOW_SYS},
{sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS},
@@ -833,6 +854,8 @@ SHOW_VAR init_vars[]= {
{"log_bin", (char*) &opt_bin_log, SHOW_BOOL},
{sys_trust_function_creators.name,(char*) &sys_trust_function_creators, SHOW_SYS},
{"log_error", (char*) log_error_file, SHOW_CHAR},
+ {sys_log_queries_not_using_indexes.name,
+ (char*) &sys_log_queries_not_using_indexes, SHOW_SYS},
#ifdef HAVE_REPLICATION
{"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL},
#endif
@@ -962,6 +985,11 @@ SHOW_VAR init_vars[]= {
{sys_sql_mode.name, (char*) &sys_sql_mode, SHOW_SYS},
{"sql_notes", (char*) &sys_sql_notes, SHOW_SYS},
{"sql_warnings", (char*) &sys_sql_warnings, SHOW_SYS},
+ {sys_ssl_ca.name, (char*) &sys_ssl_ca, SHOW_SYS},
+ {sys_ssl_capath.name, (char*) &sys_ssl_capath, SHOW_SYS},
+ {sys_ssl_cert.name, (char*) &sys_ssl_cert, SHOW_SYS},
+ {sys_ssl_cipher.name, (char*) &sys_ssl_cipher, SHOW_SYS},
+ {sys_ssl_key.name, (char*) &sys_ssl_key, SHOW_SYS},
{sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS},
#ifdef HAVE_REPLICATION
{sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS},
@@ -983,7 +1011,7 @@ SHOW_VAR init_vars[]= {
{"time_zone", (char*) &sys_time_zone, SHOW_SYS},
{sys_timed_mutexes.name, (char*) &sys_timed_mutexes, SHOW_SYS},
{sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS},
- {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR},
+ {sys_tmpdir.name, (char*) &sys_tmpdir, SHOW_SYS},
{sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size,
SHOW_SYS},
{sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS},
@@ -2700,7 +2728,7 @@ bool sys_var_max_user_conn::check(THD *thd, set_var *var)
{
/*
Per-session values of max_user_connections can't be set directly.
- QQ: May be we should have a separate error message for this?
+ May be we should have a separate error message for this?
*/
my_error(ER_GLOBAL_VARIABLE, MYF(0), name);
return TRUE;
@@ -2767,7 +2795,8 @@ static bool set_option_autocommit(THD *thd, set_var *var)
if ((org_options & OPTION_NOT_AUTOCOMMIT))
{
/* We changed to auto_commit mode */
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
if (ha_commit(thd))
return 1;
@@ -2855,6 +2884,31 @@ static byte *get_prepared_stmt_count(THD *thd)
return (byte*) &thd->sys_var_tmp.ulong_value;
}
+
+/*
+ Get the tmpdir that was specified or chosen by default
+
+ SYNOPSIS
+ get_tmpdir()
+ thd thread handle
+
+ DESCRIPTION
+ This is necessary because if the user does not specify a temporary
+ directory via the command line, one is chosen based on the environment
+ or system defaults. But we can't just always use mysql_tmpdir, because
+ that is actually a call to my_tmpdir() which cycles among possible
+ temporary directories.
+
+ RETURN VALUES
+ ptr pointer to NUL-terminated string
+ */
+static byte *get_tmpdir(THD *thd)
+{
+ if (opt_mysql_tmpdir)
+ return (byte *)opt_mysql_tmpdir;
+ return (byte*)mysql_tmpdir;
+}
+
/****************************************************************************
Main handling of variables:
- Initialisation
@@ -3254,7 +3308,7 @@ byte *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
handlerton *val;
val= (type == OPT_GLOBAL) ? global_system_variables.*offset :
thd->variables.*offset;
- return (byte *) val->name;
+ return (byte *) hton2plugin[val->slot]->name.str;
}
@@ -3579,6 +3633,69 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
return (byte*) thd->strdup(buf);
}
+
+/*
+ The update method of the global variable event_scheduler.
+ If event_scheduler is switched from 0 to 1 then the scheduler main
+ thread is resumed and if from 1 to 0 the scheduler thread is suspended
+
+ SYNOPSIS
+ sys_var_event_scheduler::update()
+ thd Thread context (unused)
+ var The new value
+
+ Returns
+ FALSE OK
+ TRUE Error
+*/
+
+bool
+sys_var_event_scheduler::update(THD *thd, set_var *var)
+{
+ enum Event_scheduler::enum_error_code res;
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+ /* here start the thread if not running. */
+ DBUG_ENTER("sys_var_event_scheduler::update");
+
+ DBUG_PRINT("new_value", ("%lu", (bool)var->save_result.ulong_value));
+ if (!scheduler->initialized())
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=0");
+ DBUG_RETURN(true);
+ }
+
+ if (var->save_result.ulonglong_value < 1 ||
+ var->save_result.ulonglong_value > 2)
+ {
+ char buf[64];
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "event_scheduler",
+ llstr(var->save_result.ulonglong_value, buf));
+ DBUG_RETURN(true);
+ }
+ if ((res= scheduler->suspend_or_resume(var->save_result.ulonglong_value == 1?
+ Event_scheduler::RESUME :
+ Event_scheduler::SUSPEND)))
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), (uint) res);
+ DBUG_RETURN((bool) res);
+}
+
+
+byte *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ Event_scheduler *scheduler= Event_scheduler::get_instance();
+
+ if (!scheduler->initialized())
+ thd->sys_var_tmp.long_value= 0;
+ else if (scheduler->get_state() == Event_scheduler::RUNNING)
+ thd->sys_var_tmp.long_value= 1;
+ else
+ thd->sys_var_tmp.long_value= 2;
+
+ return (byte*) &thd->sys_var_tmp;
+}
+
+
/****************************************************************************
Used templates
****************************************************************************/
diff --git a/sql/set_var.h b/sql/set_var.h
index 8076f10bb0a..1049b154d47 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -231,6 +231,35 @@ public:
};
+class sys_var_const_str_ptr :public sys_var
+{
+public:
+ char **value; // Pointer to const value
+ sys_var_const_str_ptr(const char *name_arg, char **value_arg)
+ :sys_var(name_arg),value(value_arg)
+ {}
+ bool check(THD *thd, set_var *var)
+ {
+ return 1;
+ }
+ bool update(THD *thd, set_var *var)
+ {
+ return 1;
+ }
+ SHOW_TYPE type() { return SHOW_CHAR; }
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ {
+ return (byte*) *value;
+ }
+ bool check_update_type(Item_result type)
+ {
+ return 1;
+ }
+ bool check_default(enum_var_type type) { return 1; }
+ bool is_readonly() const { return 1; }
+};
+
+
class sys_var_enum :public sys_var
{
uint *value;
@@ -842,13 +871,14 @@ public:
};
-class sys_var_event_executor :public sys_var_bool_ptr
+class sys_var_event_scheduler :public sys_var_long_ptr
{
/* We need a derived class only to have a warn_deprecated() */
public:
- sys_var_event_executor(const char *name_arg, my_bool *value_arg) :
- sys_var_bool_ptr(name_arg, value_arg) {};
+ sys_var_event_scheduler(const char *name_arg) :
+ sys_var_long_ptr(name_arg, NULL, NULL) {};
bool update(THD *thd, set_var *var);
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
extern void fix_binlog_format_after_update(THD *thd, enum_var_type type);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 1d1cc5b5056..ae5ddd31475 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -2865,30 +2865,8 @@ ER_WRONG_OUTER_JOIN 42000
swe "Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket"
ukr "ðÅÒÅÈÒÅÓÎÁ ÚÁÌÅÖΦÓÔØ Õ OUTER JOIN. ðÅÒÅצÒÔÅ ÕÍÏ×Õ ON"
ER_NULL_COLUMN_IN_INDEX 42000
- cze "Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL"
- dan "Kolonne '%-.32s' bruges som UNIQUE eller INDEX men er ikke defineret som NOT NULL"
- nla "Kolom '%-.64s' wordt gebruikt met UNIQUE of INDEX maar is niet gedefinieerd als NOT NULL"
- eng "Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
- jps "Column '%-.64s' ‚ª UNIQUE ‚© INDEX ‚ÅŽg—p‚³‚ê‚Ü‚µ‚½. ‚±‚̃Jƒ‰ƒ€‚Í NOT NULL ‚Æ’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
- est "Tulp '%-.64s' on kasutusel indeksina, kuid ei ole määratletud kui NOT NULL"
- fre "La colonne '%-.32s' fait partie d'un index UNIQUE ou INDEX mais n'est pas définie comme NOT NULL"
- ger "Spalte '%-.64s' wurde mit UNIQUE oder INDEX benutzt, ist aber nicht als NOT NULL definiert"
- greek "Ôï ðåäßï '%-.64s' ÷ñçóéìïðïéåßôáé óáí UNIQUE Þ INDEX áëëÜ äåí Ý÷åé ïñéóèåß óáí NOT NULL"
- hun "A(z) '%-.64s' oszlop INDEX vagy UNIQUE (egyedi), de a definicioja szerint nem NOT NULL"
- ita "La colonna '%-.64s' e` usata con UNIQUE o INDEX ma non e` definita come NOT NULL"
- jpn "Column '%-.64s' ¤¬ UNIQUE ¤« INDEX ¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿. ¤³¤Î¥«¥é¥à¤Ï NOT NULL ¤ÈÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó."
- kor "'%-.64s' Ä®·³ÀÌ UNIQUE³ª INDEX¸¦ »ç¿ëÇÏ¿´Áö¸¸ NOT NULLÀÌ Á¤ÀǵÇÁö ¾Ê¾Ò±º¿ä..."
- nor "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
- norwegian-ny "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
- pol "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
- por "Coluna '%-.64s' é usada com única (UNIQUE) ou índice (INDEX), mas não está definida como não-nula (NOT NULL)"
- rum "Coloana '%-.64s' e folosita cu UNIQUE sau INDEX dar fara sa fie definita ca NOT NULL"
- rus "óÔÏÌÂÅÃ '%-.64s' ÉÓÐÏÌØÚÕÅÔÓÑ × UNIQUE ÉÌÉ × INDEX, ÎÏ ÎÅ ÏÐÒÅÄÅÌÅÎ ËÁË NOT NULL"
- serbian "Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'"
- slo "Pole '%-.64s' je pou¾ité s UNIQUE alebo INDEX, ale nie je zadefinované ako NOT NULL"
- spa "Columna '%-.32s' es usada con UNIQUE o INDEX pero no está definida como NOT NULL"
- swe "Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL"
- ukr "óÔÏ×ÂÅÃØ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ Ú UNIQUE ÁÂÏ INDEX, ÁÌÅ ÎÅ ×ÉÚÎÁÞÅÎÉÊ ÑË NOT NULL"
+ eng "Table handler doesn't support NULL in given index. Please change column '%-.64s' to be NOT NULL or use another handler"
+ swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.64s' till NOT NULL eller använd en annan hanterare"
ER_CANT_FIND_UDF
cze "Nemohu na-Bèíst funkci '%-.64s'"
dan "Kan ikke læse funktionen '%-.64s'"
@@ -3957,7 +3935,7 @@ ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
spa "Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna"
swe "Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel"
ukr "÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ"
-ER_KEY_DOES_NOT_EXITS
+ER_KEY_DOES_NOT_EXITS 42000 S1009
cze "Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje"
dan "Nøglen '%-.64s' eksisterer ikke i tabellen '%-.64s'"
nla "Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'"
@@ -5042,7 +5020,7 @@ ER_OPTION_PREVENTS_STATEMENT
ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen"
por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando"
spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando"
- swe "MySQL är startad med --skip-grant-tables. Pga av detta kan du inte använda detta kommando"
+ swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando"
ER_DUPLICATED_VALUE_IN_TYPE
eng "Column '%-.100s' has duplicated value '%-.64s' in %s"
ger "Feld '%-.100s' hat doppelten Wert '%-.64s' in %s"
@@ -5832,6 +5810,9 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT
eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
ER_PARTITION_NO_TEMPORARY
eng "Cannot create temporary table with partitions"
+ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+ eng "This partition function is not allowed"
+ swe "Denna partitioneringsfunktion är inte tillåten"
ER_DDL_LOG_ERROR
eng "Error in DDL log"
ER_NULL_IN_VALUES_LESS_THAN
@@ -5842,3 +5823,12 @@ ER_WRONG_PARTITION_NAME
swe "Felaktigt partitionsnamn"
ER_CANT_CHANGE_TX_ISOLATION 25001
eng "Transaction isolation level can't be changed while a transaction is in progress"
+ER_DUP_ENTRY_AUTOINCREMENT_CASE
+ eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
+ER_EVENT_MODIFY_QUEUE_ERROR
+ eng "Internal scheduler error %d"
+ER_EVENT_SET_VAR_ERROR
+ eng "Error during starting/stopping of the scheduler. Error code %u"
+ER_PARTITION_MERGE_ERROR
+ eng "MyISAM Merge handler cannot be used in partitioned tables"
+ swe "MyISAM Merge kan inte anändas i en partitionerad tabell"
diff --git a/sql/slave.cc b/sql/slave.cc
index 4ab9e951813..5ef91b1f0d4 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -95,6 +95,8 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
{
bool set_io = mi->slave_running, set_sql = mi->rli.slave_running;
register int tmp_mask=0;
+ DBUG_ENTER("init_thread_mask");
+
if (set_io)
tmp_mask |= SLAVE_IO;
if (set_sql)
@@ -102,6 +104,7 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
if (inverse)
tmp_mask^= (SLAVE_IO | SLAVE_SQL);
*mask = tmp_mask;
+ DBUG_VOID_RETURN;
}
@@ -111,9 +114,12 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
void lock_slave_threads(MASTER_INFO* mi)
{
+ DBUG_ENTER("lock_slave_threads");
+
//TODO: see if we can do this without dual mutex
pthread_mutex_lock(&mi->run_lock);
pthread_mutex_lock(&mi->rli.run_lock);
+ DBUG_VOID_RETURN;
}
@@ -123,9 +129,12 @@ void lock_slave_threads(MASTER_INFO* mi)
void unlock_slave_threads(MASTER_INFO* mi)
{
+ DBUG_ENTER("unlock_slave_threads");
+
//TODO: see if we can do this without dual mutex
pthread_mutex_unlock(&mi->rli.run_lock);
pthread_mutex_unlock(&mi->run_lock);
+ DBUG_VOID_RETURN;
}
@@ -423,6 +432,8 @@ err:
void init_slave_skip_errors(const char* arg)
{
const char *p;
+ DBUG_ENTER("init_slave_skip_errors");
+
if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
{
fprintf(stderr, "Badly out of memory, please check your system status\n");
@@ -434,7 +445,7 @@ void init_slave_skip_errors(const char* arg)
if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
{
bitmap_set_all(&slave_error_mask);
- return;
+ DBUG_VOID_RETURN;
}
for (p= arg ; *p; )
{
@@ -446,12 +457,15 @@ void init_slave_skip_errors(const char* arg)
while (!my_isdigit(system_charset_info,*p) && *p)
p++;
}
+ DBUG_VOID_RETURN;
}
void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
bool skip_lock)
{
+ DBUG_ENTER("st_relay_log_info::inc_group_relay_log_pos");
+
if (!skip_lock)
pthread_mutex_lock(&data_lock);
inc_event_relay_log_pos();
@@ -500,12 +514,14 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
pthread_cond_broadcast(&data_cond);
if (!skip_lock)
pthread_mutex_unlock(&data_lock);
+ DBUG_VOID_RETURN;
}
void st_relay_log_info::close_temporary_tables()
{
TABLE *table,*next;
+ DBUG_ENTER("st_relay_log_info::close_temporary_tables");
for (table=save_temporary_tables ; table ; table=next)
{
@@ -514,10 +530,12 @@ void st_relay_log_info::close_temporary_tables()
Don't ask for disk deletion. For now, anyway they will be deleted when
slave restarts, but it is a better intention to not delete them.
*/
+ DBUG_PRINT("info", ("table: %p", table));
close_temporary(table, 1, 0);
}
save_temporary_tables= 0;
slave_open_temp_tables= 0;
+ DBUG_VOID_RETURN;
}
/*
@@ -613,12 +631,13 @@ err:
int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
{
+ DBUG_ENTER("terminate_slave_threads");
+
if (!mi->inited)
- return 0; /* successfully do nothing */
+ DBUG_RETURN(0); /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
pthread_mutex_t *sql_cond_lock,*io_cond_lock;
- DBUG_ENTER("terminate_slave_threads");
sql_cond_lock=sql_lock;
io_cond_lock=io_lock;
@@ -704,9 +723,10 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
{
pthread_t th;
ulong start_id;
- DBUG_ASSERT(mi->inited);
DBUG_ENTER("start_slave_thread");
+ DBUG_ASSERT(mi->inited);
+
if (start_lock)
pthread_mutex_lock(start_lock);
if (!server_id)
@@ -810,8 +830,10 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
#ifdef NOT_USED_YET
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
{
+ DBUG_ENTER("end_slave_on_walk");
+
end_master_info(mi);
- return 0;
+ DBUG_RETURN(0);
}
#endif
@@ -825,6 +847,8 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
void end_slave()
{
+ DBUG_ENTER("end_slave");
+
/*
This is called when the server terminates, in close_connections().
It terminates slave threads. However, some CHANGE MASTER etc may still be
@@ -846,19 +870,24 @@ void end_slave()
active_mi= 0;
}
pthread_mutex_unlock(&LOCK_active_mi);
+ DBUG_VOID_RETURN;
}
static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
{
+ DBUG_ENTER("io_slave_killed");
+
DBUG_ASSERT(mi->io_thd == thd);
DBUG_ASSERT(mi->slave_running); // tracking buffer overrun
- return mi->abort_slave || abort_loop || thd->killed;
+ DBUG_RETURN(mi->abort_slave || abort_loop || thd->killed);
}
static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
{
+ DBUG_ENTER("sql_slave_killed");
+
DBUG_ASSERT(rli->sql_thd == thd);
DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
if (abort_loop || thd->killed || rli->abort_slave)
@@ -873,7 +902,7 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
is actively working.
*/
if (!rli->unsafe_to_stop_at)
- return 1;
+ DBUG_RETURN(1);
DBUG_PRINT("info", ("Slave SQL thread is in an unsafe situation, giving "
"it some grace period"));
if (difftime(time(0), rli->unsafe_to_stop_at) > 60)
@@ -885,10 +914,10 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
"There is a risk of duplicate updates when the slave "
"SQL thread is restarted. Please check your tables' "
"contents after restart.");
- return 1;
+ DBUG_RETURN(1);
}
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -917,6 +946,8 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli,
char buff[MAX_SLAVE_ERRMSG], *pbuff= buff;
uint pbuffsize= sizeof(buff);
va_list args;
+ DBUG_ENTER("slave_print_msg");
+
va_start(args,msg);
switch (level)
{
@@ -943,7 +974,7 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli,
break;
default:
DBUG_ASSERT(0); // should not come here
- return; // don't crash production builds, just do nothing
+ DBUG_VOID_RETURN; // don't crash production builds, just do nothing
}
my_vsnprintf(pbuff, pbuffsize, msg, args);
/* If the msg string ends with '.', do not add a ',' it would be ugly */
@@ -951,6 +982,7 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli,
(*report_function)("Slave: %s Error_code: %d", pbuff, err_code);
else
(*report_function)("Slave: %s, Error_code: %d", pbuff, err_code);
+ DBUG_VOID_RETURN;
}
/*
@@ -962,9 +994,12 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli,
void skip_load_data_infile(NET *net)
{
+ DBUG_ENTER("skip_load_data_infile");
+
(void)net_request_file(net, "/dev/null");
(void)my_net_read(net); // discard response
(void)net_write_command(net, 0, "", 0, "", 0); // Send ok
+ DBUG_VOID_RETURN;
}
@@ -983,13 +1018,17 @@ bool net_request_file(NET* net, const char* fname)
const char *print_slave_db_safe(const char* db)
{
- return (db ? db : "");
+ DBUG_ENTER("*print_slave_db_safe");
+
+ DBUG_RETURN((db ? db : ""));
}
static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
uint length;
+ DBUG_ENTER("init_strvar_from_file");
+
if ((length=my_b_gets(f,var, max_size)))
{
char* last_p = var + length -1;
@@ -1004,32 +1043,34 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
int c;
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
}
- return 0;
+ DBUG_RETURN(0);
}
else if (default_val)
{
strmake(var, default_val, max_size-1);
- return 0;
+ DBUG_RETURN(0);
}
- return 1;
+ DBUG_RETURN(1);
}
static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
+ DBUG_ENTER("init_intvar_from_file");
+
if (my_b_gets(f, buf, sizeof(buf)))
{
*var = atoi(buf);
- return 0;
+ DBUG_RETURN(0);
}
else if (default_val)
{
*var = default_val;
- return 0;
+ DBUG_RETURN(0);
}
- return 1;
+ DBUG_RETURN(1);
}
/*
@@ -1049,6 +1090,7 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
{
const char* errmsg= 0;
+ DBUG_ENTER("get_master_version_and_clock");
/*
Free old description_event_for_queue (that is needed if we are in
@@ -1104,14 +1146,14 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
if (errmsg)
{
sql_print_error(errmsg);
- return 1;
+ DBUG_RETURN(1);
}
/* as we are here, we tried to allocate the event */
if (!mi->rli.relay_log.description_event_for_queue)
{
sql_print_error("Slave I/O thread failed to create a default Format_description_log_event");
- return 1;
+ DBUG_RETURN(1);
}
/*
@@ -1227,10 +1269,10 @@ err:
if (errmsg)
{
sql_print_error(errmsg);
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -1257,7 +1299,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
handler *file;
ulong save_options;
NET *net= &mysql->net;
- DBUG_ENTER("create_table_from_dump");
+ DBUG_ENTER("create_table_from_dump");
packet_len= my_net_read(net); // read create table statement
if (packet_len == packet_error)
@@ -1666,7 +1708,6 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
MASTER_INFO* mi = rli->mi;
const char *save_proc_info;
THD* thd = mi->io_thd;
-
DBUG_ENTER("wait_for_relay_log_space");
pthread_mutex_lock(&rli->log_space_lock);
@@ -1725,6 +1766,8 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
{
RELAY_LOG_INFO *rli= &mi->rli;
pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
+ DBUG_ENTER("write_ignored_events_info_to_relay_log");
+
DBUG_ASSERT(thd == mi->io_thd);
pthread_mutex_lock(log_lock);
if (rli->ign_master_log_name_end[0])
@@ -1755,11 +1798,14 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
}
else
pthread_mutex_unlock(log_lock);
+ DBUG_VOID_RETURN;
}
void init_master_info_with_options(MASTER_INFO* mi)
{
+ DBUG_ENTER("init_master_info_with_options");
+
mi->master_log_name[0] = 0;
mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
@@ -1783,13 +1829,17 @@ void init_master_info_with_options(MASTER_INFO* mi)
strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
if (master_ssl_key)
strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
+ DBUG_VOID_RETURN;
}
void clear_slave_error(RELAY_LOG_INFO* rli)
{
+ DBUG_ENTER("clear_slave_error");
+
/* Clear the errors displayed by SHOW SLAVE STATUS */
rli->last_slave_error[0]= 0;
rli->last_slave_errno= 0;
+ DBUG_VOID_RETURN;
}
/*
@@ -1800,9 +1850,12 @@ void clear_slave_error(RELAY_LOG_INFO* rli)
*/
void clear_until_condition(RELAY_LOG_INFO* rli)
{
+ DBUG_ENTER("clear_until_condition");
+
rli->until_condition= RELAY_LOG_INFO::UNTIL_NONE;
rli->until_log_name[0]= 0;
rli->until_log_pos= 0;
+ DBUG_VOID_RETURN;
}
@@ -2031,9 +2084,10 @@ int register_slave_on_master(MYSQL* mysql)
{
char buf[1024], *pos= buf;
uint report_host_len, report_user_len=0, report_password_len=0;
+ DBUG_ENTER("register_slave_on_master");
if (!report_host)
- return 0;
+ DBUG_RETURN(0);
report_host_len= strlen(report_host);
if (report_user)
report_user_len= strlen(report_user);
@@ -2042,7 +2096,7 @@ int register_slave_on_master(MYSQL* mysql)
/* 30 is a good safety margin */
if (report_host_len + report_user_len + report_password_len + 30 >
sizeof(buf))
- return 0; // safety
+ DBUG_RETURN(0); // safety
int4store(pos, server_id); pos+= 4;
pos= net_store_data(pos, report_host, report_host_len);
@@ -2059,9 +2113,9 @@ int register_slave_on_master(MYSQL* mysql)
sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
mysql_errno(mysql),
mysql_error(mysql));
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -2313,6 +2367,8 @@ st_relay_log_info::st_relay_log_info()
m_reload_flags(RELOAD_NONE_F),
unsafe_to_stop_at(0)
{
+ DBUG_ENTER("st_relay_log_info::st_relay_log_info");
+
group_relay_log_name[0]= event_relay_log_name[0]=
group_master_log_name[0]= 0;
last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0;
@@ -2327,11 +2383,14 @@ st_relay_log_info::st_relay_log_info()
pthread_cond_init(&stop_cond, NULL);
pthread_cond_init(&log_space_cond, NULL);
relay_log.init_pthread_objects();
+ DBUG_VOID_RETURN;
}
st_relay_log_info::~st_relay_log_info()
{
+ DBUG_ENTER("st_relay_log_info::~st_relay_log_info");
+
pthread_mutex_destroy(&run_lock);
pthread_mutex_destroy(&data_lock);
pthread_mutex_destroy(&log_space_lock);
@@ -2340,6 +2399,7 @@ st_relay_log_info::~st_relay_log_info()
pthread_cond_destroy(&stop_cond);
pthread_cond_destroy(&log_space_cond);
relay_log.cleanup();
+ DBUG_VOID_RETURN;
}
/*
@@ -2371,14 +2431,16 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
longlong log_pos,
longlong timeout)
{
- if (!inited)
- return -1;
int event_count = 0;
ulong init_abort_pos_wait;
int error=0;
struct timespec abstime; // for timeout checking
const char *msg;
- DBUG_ENTER("wait_for_pos");
+ DBUG_ENTER("st_relay_log_info::wait_for_pos");
+
+ if (!inited)
+ DBUG_RETURN(-1);
+
DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu",
log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
@@ -2546,13 +2608,18 @@ improper_arguments: %d timed_out: %d",
void set_slave_thread_options(THD* thd)
{
+ DBUG_ENTER("set_slave_thread_options");
+
thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
OPTION_AUTO_IS_NULL;
thd->variables.completion_type= 0;
+ DBUG_VOID_RETURN;
}
void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
{
+ DBUG_ENTER("set_slave_thread_default_charset");
+
thd->variables.character_set_client=
global_system_variables.character_set_client;
thd->variables.collation_connection=
@@ -2561,6 +2628,7 @@ void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
global_system_variables.collation_server;
thd->update_charset();
rli->cached_charset_invalidate();
+ DBUG_VOID_RETURN;
}
/*
@@ -2622,6 +2690,8 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
{
int nap_time;
thr_alarm_t alarmed;
+ DBUG_ENTER("safe_sleep");
+
thr_alarm_init(&alarmed);
time_t start_time= time((time_t*) 0);
time_t end_time= start_time+sec;
@@ -2639,10 +2709,10 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
thr_end_alarm(&alarmed);
if ((*thread_killed)(thd,thread_killed_arg))
- return 1;
+ DBUG_RETURN(1);
start_time=time((time_t*) 0);
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -2684,13 +2754,15 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
{
char buf[1024];
+ DBUG_ENTER("request_table_dump");
+
char * p = buf;
uint table_len = (uint) strlen(table);
uint db_len = (uint) strlen(db);
if (table_len + db_len > sizeof(buf) - 2)
{
sql_print_error("request_table_dump: Buffer overrun");
- return 1;
+ DBUG_RETURN(1);
}
*p++ = db_len;
@@ -2703,10 +2775,10 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
{
sql_print_error("request_table_dump: Error sending the table dump \
command");
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -2730,6 +2802,7 @@ command");
static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
{
ulong len;
+ DBUG_ENTER("read_event");
*suppress_warnings= 0;
/*
@@ -2738,7 +2811,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
*/
#ifndef DBUG_OFF
if (disconnect_slave_event_count && !(mi->events_till_disconnect--))
- return packet_error;
+ DBUG_RETURN(packet_error);
#endif
len = net_safe_read(mysql);
@@ -2756,7 +2829,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
else
sql_print_error("Error reading packet from server: %s ( server_errno=%d)",
mysql_error(mysql), mysql_errno(mysql));
- return packet_error;
+ DBUG_RETURN(packet_error);
}
/* Check if eof packet */
@@ -2765,25 +2838,27 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
sql_print_information("Slave: received end packet from server, apparent "
"master shutdown: %s",
mysql_error(mysql));
- return packet_error;
+ DBUG_RETURN(packet_error);
}
DBUG_PRINT("info",( "len=%u, net->read_pos[4] = %d\n",
len, mysql->net.read_pos[4]));
- return len - 1;
+ DBUG_RETURN(len - 1);
}
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
{
+ DBUG_ENTER("check_expected_error");
+
switch (expected_error) {
case ER_NET_READ_ERROR:
case ER_NET_ERROR_ON_WRITE:
case ER_SERVER_SHUTDOWN:
case ER_NEW_ABORTING_CONNECTION:
- return 1;
+ DBUG_RETURN(1);
default:
- return 0;
+ DBUG_RETURN(0);
}
}
@@ -2819,6 +2894,7 @@ bool st_relay_log_info::is_until_satisfied()
{
const char *log_name;
ulonglong log_pos;
+ DBUG_ENTER("st_relay_log_info::is_until_satisfied");
DBUG_ASSERT(until_condition != UNTIL_NONE);
@@ -2865,34 +2941,39 @@ bool st_relay_log_info::is_until_satisfied()
/* Probably error so we aborting */
sql_print_error("Slave SQL thread is stopped because UNTIL "
"condition is bad.");
- return TRUE;
+ DBUG_RETURN(TRUE);
}
}
else
- return until_log_pos == 0;
+ DBUG_RETURN(until_log_pos == 0);
}
- return ((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL &&
+ DBUG_RETURN(((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL &&
log_pos >= until_log_pos) ||
- until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER);
+ until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER));
}
void st_relay_log_info::cached_charset_invalidate()
{
+ DBUG_ENTER("st_relay_log_info::cached_charset_invalidate");
+
/* Full of zeroes means uninitialized. */
bzero(cached_charset, sizeof(cached_charset));
+ DBUG_VOID_RETURN;
}
bool st_relay_log_info::cached_charset_compare(char *charset)
{
+ DBUG_ENTER("st_relay_log_info::cached_charset_compare");
+
if (bcmp(cached_charset, charset, sizeof(cached_charset)))
{
memcpy(cached_charset, charset, sizeof(cached_charset));
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -2904,8 +2985,10 @@ bool st_relay_log_info::cached_charset_compare(char *charset)
*/
static int has_temporary_error(THD *thd)
{
+ DBUG_ENTER("has_temporary_error");
+
if (thd->is_fatal_error)
- return 0;
+ DBUG_RETURN(0);
/*
Temporary error codes:
@@ -2914,7 +2997,7 @@ static int has_temporary_error(THD *thd)
*/
if (thd->net.last_errno == ER_LOCK_DEADLOCK ||
thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT)
- return 1;
+ DBUG_RETURN(1);
#ifdef HAVE_NDB_BINLOG
/*
@@ -2928,17 +3011,19 @@ static int has_temporary_error(THD *thd)
switch (err->code)
{
case ER_GET_TEMPORARY_ERRMSG:
- return 1;
+ DBUG_RETURN(1);
default:
break;
}
}
#endif
- return 0;
+ DBUG_RETURN(0);
}
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
+ DBUG_ENTER("exec_relay_log_event");
+
/*
We acquire this mutex since we need it for all operations except
event execution. But we will release it in places where we will
@@ -2965,7 +3050,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
*/
rli->abort_slave= 1;
pthread_mutex_unlock(&rli->data_lock);
- return 1;
+ DBUG_RETURN(1);
}
Log_event * ev = next_event(rli);
@@ -2976,7 +3061,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
pthread_mutex_unlock(&rli->data_lock);
delete ev;
- return 1;
+ DBUG_RETURN(1);
}
if (ev)
{
@@ -3044,7 +3129,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
--rli->slave_skip_counter;
pthread_mutex_unlock(&rli->data_lock);
delete ev;
- return 0; // avoid infinite update loops
+ DBUG_RETURN(0); // avoid infinite update loops
}
pthread_mutex_unlock(&rli->data_lock);
@@ -3125,13 +3210,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
*/
rli->trans_retries= 0; // restart from fresh
}
- }
- return exec_res;
+ }
+ DBUG_RETURN(exec_res);
}
- else
- {
- pthread_mutex_unlock(&rli->data_lock);
- slave_print_msg(ERROR_LEVEL, rli, 0, "\
+ pthread_mutex_unlock(&rli->data_lock);
+ slave_print_msg(ERROR_LEVEL, rli, 0, "\
Could not parse relay log event entry. The possible reasons are: the master's \
binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
binary log), the slave's relay log is corrupted (you can check this by running \
@@ -3140,8 +3223,7 @@ or slave's MySQL code. If you want to check the master's binary log or slave's \
relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' \
on this slave.\
");
- return 1;
- }
+ DBUG_RETURN(1);
}
@@ -3461,6 +3543,7 @@ pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd; /* needs to be first for thread_stack */
char llbuff[22],llbuff1[22];
+
RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli;
const char *errmsg;
@@ -4060,16 +4143,18 @@ err:
static int queue_old_event(MASTER_INFO *mi, const char *buf,
ulong event_len)
{
+ DBUG_ENTER("queue_old_event");
+
switch (mi->rli.relay_log.description_event_for_queue->binlog_version)
{
case 1:
- return queue_binlog_ver_1_event(mi,buf,event_len);
+ DBUG_RETURN(queue_binlog_ver_1_event(mi,buf,event_len));
case 3:
- return queue_binlog_ver_3_event(mi,buf,event_len);
+ DBUG_RETURN(queue_binlog_ver_3_event(mi,buf,event_len));
default: /* unsupported format; eg version 2 */
DBUG_PRINT("info",("unsupported binlog format %d in queue_old_event()",
mi->rli.relay_log.description_event_for_queue->binlog_version));
- return 1;
+ DBUG_RETURN(1);
}
}
@@ -4282,7 +4367,9 @@ void end_relay_log_info(RELAY_LOG_INFO* rli)
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{
- return connect_to_master(thd, mysql, mi, 0, 0);
+ DBUG_ENTER("safe_connect");
+
+ DBUG_RETURN(connect_to_master(thd, mysql, mi, 0, 0));
}
@@ -4439,9 +4526,10 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
bool flush_relay_log_info(RELAY_LOG_INFO* rli)
{
bool error=0;
+ DBUG_ENTER("flush_relay_log_info");
if (unlikely(rli->no_storage))
- return 0;
+ DBUG_RETURN(0);
IO_CACHE *file = &rli->info_file;
char buff[FN_REFLEN*2+22*2+4], *pos;
@@ -4461,7 +4549,7 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
error=1;
/* Flushing the relay log is done by the slave I/O thread */
- return error;
+ DBUG_RETURN(error);
}
@@ -4471,9 +4559,9 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
{
+ DBUG_ENTER("reopen_relay_log");
DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
DBUG_ASSERT(rli->cur_log_fd == -1);
- DBUG_ENTER("reopen_relay_log");
IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
if ((rli->cur_log_fd=open_binlog(cur_log,rli->event_relay_log_name,
@@ -4494,11 +4582,11 @@ static Log_event* next_event(RELAY_LOG_INFO* rli)
{
Log_event* ev;
IO_CACHE* cur_log = rli->cur_log;
- pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
+ pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
const char* errmsg=0;
THD* thd = rli->sql_thd;
-
DBUG_ENTER("next_event");
+
DBUG_ASSERT(thd != 0);
#ifndef DBUG_OFF
@@ -4909,12 +4997,16 @@ static int reload_entry_compare(const void *lhs, const void *rhs)
{
const char *lstr = static_cast<const char *>(lhs);
const char *rstr = static_cast<const st_reload_entry*>(rhs)->table;
- return strcmp(lstr, rstr);
+ DBUG_ENTER("reload_entry_compare");
+
+ DBUG_RETURN(strcmp(lstr, rstr));
}
void st_relay_log_info::touching_table(char const* db, char const* table,
ulong table_id)
{
+ DBUG_ENTER("st_relay_log_info::touching_table");
+
if (strcmp(db,"mysql") == 0)
{
#if defined(HAVE_BSEARCH) && defined(HAVE_SIZE_T)
@@ -4935,10 +5027,13 @@ void st_relay_log_info::touching_table(char const* db, char const* table,
if (entry)
m_reload_flags|= entry->flag;
}
+ DBUG_VOID_RETURN;
}
void st_relay_log_info::transaction_end(THD* thd)
{
+ DBUG_ENTER("st_relay_log_info::transaction_end");
+
if (m_reload_flags != RELOAD_NONE_F)
{
if (m_reload_flags & RELOAD_ACCESS_F)
@@ -4949,11 +5044,14 @@ void st_relay_log_info::transaction_end(THD* thd)
m_reload_flags= RELOAD_NONE_F;
}
+ DBUG_VOID_RETURN;
}
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
void st_relay_log_info::cleanup_context(THD *thd, bool error)
{
+ DBUG_ENTER("st_relay_log_info::cleanup_context");
+
DBUG_ASSERT(sql_thd == thd);
/*
1) Instances of Table_map_log_event, if ::exec_event() was called on them,
@@ -4976,6 +5074,7 @@ void st_relay_log_info::cleanup_context(THD *thd, bool error)
close_thread_tables(thd);
clear_tables_to_lock();
unsafe_to_stop_at= 0;
+ DBUG_VOID_RETURN;
}
#endif
diff --git a/sql/sp.cc b/sql/sp.cc
index 6f074fd7dce..653c04ee11a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -137,6 +137,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
mysql_proc_table_exists= 0;
DBUG_RETURN(0);
}
+ table->use_all_columns();
DBUG_ASSERT(table->s->system_table);
@@ -182,6 +183,8 @@ static TABLE *open_proc_table_for_update(THD *thd)
tables.lock_type= TL_WRITE;
table= open_ltable(thd, &tables, TL_WRITE);
+ if (table)
+ table->use_all_columns();
/*
Under explicit LOCK TABLES or in prelocked mode we should not
@@ -408,15 +411,13 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong old_sql_mode= thd->variables.sql_mode;
ha_rows old_select_limit= thd->variables.select_limit;
sp_rcontext *old_spcont= thd->spcont;
-
+
char definer_user_name_holder[USERNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
- USERNAME_LENGTH);
+ LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
char definer_host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
- HOSTNAME_LENGTH);
-
+ LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
+
int ret;
thd->variables.sql_mode= sql_mode;
@@ -803,6 +804,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
TABLE_LIST *leaves= 0;
st_used_field used_fields[array_elements(init_fields)];
+ table->use_all_columns();
memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
/* Init header */
for (used_field= &used_fields[0];
@@ -836,7 +838,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
- &tables, 0, &leaves, FALSE);
+ &tables, &leaves, FALSE);
for (used_field= &used_fields[0];
used_field->field_name;
used_field++)
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index de56e261bd3..b3c35ad5022 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -202,6 +202,7 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_FUNC_CODE:
case SQLCOM_SHOW_AUTHORS:
+ case SQLCOM_SHOW_CONTRIBUTORS:
case SQLCOM_REPAIR:
case SQLCOM_BACKUP_TABLE:
case SQLCOM_RESTORE_TABLE:
@@ -249,6 +250,7 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_TRUNCATE:
case SQLCOM_COMMIT:
case SQLCOM_ROLLBACK:
+ case SQLCOM_LOAD:
case SQLCOM_LOAD_MASTER_DATA:
case SQLCOM_LOCK_TABLES:
case SQLCOM_CREATE_PROCEDURE:
@@ -1823,10 +1825,10 @@ void
sp_head::set_definer(const char *definer, uint definerlen)
{
char user_name_holder[USERNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH);
+ LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
char host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH);
+ LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
parse_user(definer, definerlen, user_name.str, &user_name.length,
host_name.str, &host_name.length);
@@ -3440,7 +3442,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
table->table_name= thd->strmake(name, table->table_name_length);
table->alias= thd->strdup(name);
table->lock_type= locktype;
- table->select_lex= lex->current_select; // QQ?
+ table->select_lex= lex->current_select;
table->cacheable_table= 1;
lex->add_to_query_tables(table);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index e91653f79d5..02f1525f2ad 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -34,8 +34,11 @@ static Geometry::Class_info **ci_collection_end=
Geometry::Class_info::Class_info(const char *name, int type_id,
void(*create_func)(void *)):
- m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
+ m_type_id(type_id), m_create_func(create_func)
{
+ m_name.str= (char *) name;
+ m_name.length= strlen(name);
+
ci_collection[type_id]= this;
}
@@ -826,7 +829,6 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const
double x, y;
get_point(&x, &y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
- /* QQ: Is the following prev_x+x right ? */
lr_area+= (prev_x + x)* (prev_y - y);
prev_x= x;
prev_y= y;
@@ -949,7 +951,6 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
double x, y;
get_point(&x, &y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
- /* QQ: Is the following prev_x+x right ? */
cur_area+= (prev_x + x) * (prev_y - y);
cur_cx+= x;
cur_cy+= y;
diff --git a/sql/spatial.h b/sql/spatial.h
index a6f74a1ada0..36949ff5014 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -200,7 +200,7 @@ public:
class Class_info
{
public:
- LEX_STRING_WITH_INIT m_name;
+ LEX_STRING m_name;
int m_type_id;
void (*m_create_func)(void *);
Class_info(const char *name, int type_id, void(*create_func)(void *));
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index bc377a0ec16..4c2dfac6b8b 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -323,6 +323,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
while (!(read_record_info.read_record(&read_record_info)))
{
@@ -342,7 +343,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
"case that has been forced to lowercase because "
"lower_case_table_names is set. It will not be "
"possible to remove this privilege using REVOKE.",
- host.host.hostname, host.db);
+ host.host.hostname ? host.host.hostname : "",
+ host.db ? host.db : "");
}
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
@@ -351,7 +353,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
sql_print_warning("'host' entry '%s|%s' "
"ignored in --skip-name-resolve mode.",
- host.host.hostname, host.db?host.db:"");
+ host.host.hostname ? host.host.hostname : "",
+ host.db ? host.db : "");
continue;
}
#ifndef TO_BE_REMOVED
@@ -369,6 +372,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
freeze_size(&acl_hosts);
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
password_length= table->field[2]->field_length /
table->field[2]->charset()->mbmaxlen;
@@ -421,7 +425,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
sql_print_warning("'user' entry '%s@%s' "
"ignored in --skip-name-resolve mode.",
- user.user, user.host.hostname);
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : "");
continue;
}
@@ -544,8 +549,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
#endif
}
VOID(push_dynamic(&acl_users,(gptr) &user));
- if (!user.host.hostname || user.host.hostname[0] == wild_many &&
- !user.host.hostname[1])
+ if (!user.host.hostname ||
+ (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect
}
}
@@ -555,6 +560,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
freeze_size(&acl_users);
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
while (!(read_record_info.read_record(&read_record_info)))
{
@@ -571,7 +577,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
sql_print_warning("'db' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- db.db, db.user, db.host.hostname);
+ db.db,
+ db.user ? db.user : "",
+ db.host.hostname ? db.host.hostname : "");
continue;
}
db.access=get_access(table,3);
@@ -590,7 +598,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
"case that has been forced to lowercase because "
"lower_case_table_names is set. It will not be "
"possible to remove this privilege using REVOKE.",
- db.db, db.user, db.host.hostname, db.host.hostname);
+ db.db,
+ db.user ? db.user : "",
+ db.host.hostname ? db.host.hostname : "");
}
}
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
@@ -1088,6 +1098,8 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
sctx->master_access= 0;
sctx->db_access= 0;
+ sctx->priv_user= (char *) "";
+ *sctx->priv_host= 0;
/*
Find acl entry in user database.
@@ -1162,8 +1174,7 @@ static void acl_update_user(const char *user, const char *host,
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
if (!acl_user->user && !user[0] ||
- acl_user->user &&
- !strcmp(user,acl_user->user))
+ acl_user->user && !strcmp(user,acl_user->user))
{
if (!acl_user->host.hostname && !host[0] ||
acl_user->host.hostname &&
@@ -1226,8 +1237,8 @@ static void acl_insert_user(const char *user, const char *host,
set_user_salt(&acl_user, password, password_len);
VOID(push_dynamic(&acl_users,(gptr) &acl_user));
- if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
- && !acl_user.host.hostname[1])
+ if (!acl_user.host.hostname ||
+ (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect /* purecov: tested */
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
@@ -1287,7 +1298,7 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
ACL_DB acl_db;
safe_mutex_assert_owner(&acl_cache->lock);
acl_db.user=strdup_root(&mem,user);
- update_hostname(&acl_db.host,strdup_root(&mem,host));
+ update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0);
acl_db.db=strdup_root(&mem,db);
acl_db.access=privileges;
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
@@ -1674,11 +1685,10 @@ find_acl_user(const char *host, const char *user, my_bool exact)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
- user,
- acl_user->user ? acl_user->user : "",
- host,
- acl_user->host.hostname ? acl_user->host.hostname :
- ""));
+ user, acl_user->user ? acl_user->user : "",
+ host,
+ acl_user->host.hostname ? acl_user->host.hostname :
+ ""));
if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user))
{
@@ -1728,7 +1738,7 @@ static const char *calc_ip(const char *ip, long *val, char end)
static void update_hostname(acl_host_and_ip *host, const char *hostname)
{
- host->hostname=(char*) hostname; // This will not be modified!
+ host->hostname=(char*) hostname; // This will not be modified!
if (!hostname ||
(!(hostname=calc_ip(hostname,&host->ip,'/')) ||
!(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
@@ -1748,8 +1758,8 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
}
return (!host->hostname ||
(hostname && !wild_case_compare(system_charset_info,
- hostname,host->hostname)) ||
- (ip && !wild_compare(ip,host->hostname,0)));
+ hostname, host->hostname)) ||
+ (ip && !wild_compare(ip, host->hostname, 0)));
}
bool hostname_requires_resolving(const char *hostname)
@@ -1795,14 +1805,15 @@ static bool update_user_table(THD *thd, TABLE *table,
DBUG_ENTER("update_user_table");
DBUG_PRINT("enter",("user: %s host: %s",user,host));
+ table->use_all_columns();
table->field[0]->store(host,(uint) strlen(host), system_charset_info);
table->field[1]->store(user,(uint) strlen(user), system_charset_info);
key_copy((byte *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read_idx(table->record[0], 0,
- (byte *) user_key, table->key_info->key_length,
+ (byte *) user_key,
+ table->key_info->key_length,
HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
@@ -1885,12 +1896,14 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
password=combo.password.str;
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->use_all_columns();
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
+ table->field[1]->store(combo.user.str,combo.user.length,
+ system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
HA_READ_KEY_EXACT))
@@ -2026,7 +2039,6 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
We should NEVER delete from the user table, as a uses can still
use mysqld even if he doesn't have any privileges in the user table!
*/
- table->file->ha_retrieve_all_cols();
if (cmp_record(table,record[1]) &&
(error=table->file->ha_update_row(table->record[1],table->record[0])))
{ // This should never happen
@@ -2102,13 +2114,15 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->use_all_columns();
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read_idx(table->record[0],0,
user_key, table->key_info->key_length,
HA_READ_KEY_EXACT))
@@ -2120,9 +2134,11 @@ static int replace_db_table(TABLE *table, const char *db,
}
old_row_exists = 0;
restore_record(table, s->default_values);
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
}
else
{
@@ -2144,18 +2160,17 @@ static int replace_db_table(TABLE *table, const char *db,
/* update old existing row */
if (rights)
{
- table->file->ha_retrieve_all_cols();
- if ((error=table->file->ha_update_row(table->record[1],
- table->record[0])))
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])))
goto table_error; /* purecov: deadcode */
}
else /* must have been a revoke of all privileges */
{
- if ((error = table->file->ha_delete_row(table->record[1])))
+ if ((error= table->file->ha_delete_row(table->record[1])))
goto table_error; /* purecov: deadcode */
}
}
- else if (rights && (error=table->file->ha_write_row(table->record[0])))
+ else if (rights && (error= table->file->ha_write_row(table->record[0])))
{
if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
goto table_error; /* purecov: deadcode */
@@ -2311,7 +2326,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
uint key_prefix_len;
KEY_PART_INFO *key_part= col_privs->key_info->key_part;
col_privs->field[0]->store(host.hostname,
- host.hostname ? (uint) strlen(host.hostname) : 0,
+ host.hostname ? (uint) strlen(host.hostname) :
+ 0,
system_charset_info);
col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
@@ -2397,7 +2413,8 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
{
if (exact)
{
- if ((host &&
+ if (!grant_name->host.hostname ||
+ (host &&
!my_strcasecmp(system_charset_info, host,
grant_name->host.hostname)) ||
(ip && !strcmp(ip, grant_name->host.hostname)))
@@ -2452,6 +2469,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
KEY_PART_INFO *key_part= table->key_info->key_part;
DBUG_ENTER("replace_column_table");
+ table->use_all_columns();
table->field[0]->store(combo.host.str,combo.host.length,
system_charset_info);
table->field[1]->store(db,(uint) strlen(db),
@@ -2487,7 +2505,6 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read(table->record[0], user_key,
table->key_info->key_length,
HA_READ_KEY_EXACT))
@@ -2565,7 +2582,6 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read(table->record[0], user_key,
key_prefix_length,
HA_READ_KEY_EXACT))
@@ -2655,16 +2671,19 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
DBUG_RETURN(-1); /* purecov: deadcode */
}
+ table->use_all_columns();
restore_record(table, s->default_values); // Get empty record
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
- table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name),
+ system_charset_info);
store_record(table,record[1]); // store at pos 1
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->ha_retrieve_all_cols();
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
HA_READ_KEY_EXACT))
@@ -2777,6 +2796,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
DBUG_RETURN(-1);
}
+ table->use_all_columns();
restore_record(table, s->default_values); // Get empty record
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
@@ -3473,10 +3493,14 @@ static my_bool grant_load(TABLE_LIST *tables)
0,0);
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
- t_table = tables[0].table; c_table = tables[1].table;
+ t_table = tables[0].table;
+ c_table = tables[1].table;
p_table= tables[2].table;
t_table->file->ha_index_init(0, 1);
p_table->file->ha_index_init(0, 1);
+ t_table->use_all_columns();
+ c_table->use_all_columns();
+ p_table->use_all_columns();
if (!t_table->file->index_first(t_table->record[0]))
{
memex_ptr= &memex;
@@ -3484,7 +3508,7 @@ static my_bool grant_load(TABLE_LIST *tables)
do
{
GRANT_TABLE *mem_check;
- if (!(mem_check=new GRANT_TABLE(t_table,c_table)))
+ if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table)))
{
/* This could only happen if we are out memory */
grant_option= FALSE;
@@ -3497,8 +3521,10 @@ static my_bool grant_load(TABLE_LIST *tables)
{
sql_print_warning("'tables_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- mem_check->tname, mem_check->user,
- mem_check->host, mem_check->host);
+ mem_check->tname,
+ mem_check->user ? mem_check->user : "",
+ mem_check->host.hostname ?
+ mem_check->host.hostname : "");
continue;
}
}
@@ -3522,7 +3548,7 @@ static my_bool grant_load(TABLE_LIST *tables)
{
GRANT_NAME *mem_check;
HASH *hash;
- if (!(mem_check=new GRANT_NAME(p_table)))
+ if (!(mem_check=new (&memex) GRANT_NAME(p_table)))
{
/* This could only happen if we are out memory */
grant_option= FALSE;
@@ -3536,7 +3562,8 @@ static my_bool grant_load(TABLE_LIST *tables)
sql_print_warning("'procs_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
mem_check->tname, mem_check->user,
- mem_check->host);
+ mem_check->host.hostname ?
+ mem_check->host.hostname : "");
continue;
}
}
@@ -3692,6 +3719,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
+ ulong orig_want_access= want_access;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
@@ -3713,18 +3741,22 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
}
- want_access&= ~sctx->master_access;
- if (!want_access)
- DBUG_RETURN(0); // ok
-
rw_rdlock(&LOCK_grant);
for (table= tables;
table && number-- && table != first_not_own_table;
table= table->next_global)
{
GRANT_TABLE *grant_table;
+ sctx = test(table->security_ctx) ?
+ table->security_ctx : thd->security_ctx;
+
+ want_access= orig_want_access;
+ want_access&= ~sctx->master_access;
+ if (!want_access)
+ continue; // ok
+
if (!(~table->grant.privilege & want_access) ||
- table->derived || table->schema_table || table->belong_to_view)
+ table->derived || table->schema_table)
{
/*
It is subquery in the FROM clause. VIEW set table->derived after
@@ -4243,11 +4275,6 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
DBUG_RETURN(TRUE);
}
- if (!lex_user->host.str)
- {
- lex_user->host.str= (char*) "%";
- lex_user->host.length=1;
- }
if (lex_user->host.length > HOSTNAME_LENGTH ||
lex_user->user.length > USERNAME_LENGTH)
{
@@ -4457,16 +4484,17 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
/* Add table & column access */
for (index=0 ; index < column_priv_hash.records ; index++)
{
- const char *user;
+ const char *user, *host;
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user= "";
+ if (!(host= grant_table->host.hostname))
+ host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str,
- grant_table->host.hostname))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
ulong table_access= grant_table->privs;
if ((table_access | grant_table->cols) != 0)
@@ -4593,15 +4621,16 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
/* Add routine access */
for (index=0 ; index < hash->records ; index++)
{
- const char *user;
+ const char *user, *host;
GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index);
if (!(user=grant_proc->user))
user= "";
+ if (!(host= grant_proc->host.hostname))
+ host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str,
- grant_proc->host.hostname))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
ulong proc_access= grant_proc->privs;
if (proc_access != 0)
@@ -4877,6 +4906,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
uint key_prefix_length;
DBUG_ENTER("handle_grant_table");
+ table->use_all_columns();
if (! table_no) // mysql.user table
{
/*
@@ -5055,39 +5085,37 @@ static int handle_grant_struct(uint struct_no, bool drop,
{
/*
Get a pointer to the element.
- Unfortunaltely, the host default differs for the structures.
*/
switch (struct_no) {
case 0:
acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
user= acl_user->user;
- if (!(host= acl_user->host.hostname))
- host= "%";
- break;
+ host= acl_user->host.hostname;
+ break;
case 1:
acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
user= acl_db->user;
- if (!(host= acl_db->host.hostname))
- host= "%";
+ host= acl_db->host.hostname;
break;
case 2:
grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx);
user= grant_name->user;
- if (!(host= grant_name->host.hostname))
- host= "%";
+ host= grant_name->host.hostname;
break;
case 3:
grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx);
user= grant_name->user;
- if (!(host= grant_name->host.hostname))
- host= "%";
+ host= grant_name->host.hostname;
break;
}
if (! user)
user= "";
+ if (! host)
+ host= "";
+
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
struct_no, idx, user, host));
@@ -5526,7 +5554,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
- if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
+ if (!replace_db_table(tables[1].table, acl_db->db, *lex_user,
+ ~(ulong)0, 1))
{
/*
Don't increment counter as replace_db_table deleted the
@@ -5671,8 +5700,10 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
LEX_USER lex_user;
lex_user.user.str= grant_proc->user;
lex_user.user.length= strlen(grant_proc->user);
- lex_user.host.str= grant_proc->host.hostname;
- lex_user.host.length= strlen(grant_proc->host.hostname);
+ lex_user.host.str= grant_proc->host.hostname ?
+ grant_proc->host.hostname : (char*)"";
+ lex_user.host.length= grant_proc->host.hostname ?
+ strlen(grant_proc->host.hostname) : 0;
if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
grant_proc->db, grant_proc->tname,
is_proc, ~(ulong)0, 1))
@@ -5979,16 +6010,17 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
for (index=0 ; index < column_priv_hash.records ; index++)
{
- const char *user, *is_grantable= "YES";
+ const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user= "";
+ if (!(host= grant_table->host.hostname))
+ host= "";
if (no_global_access &&
(strcmp(thd->security_ctx->priv_user, user) ||
- my_strcasecmp(system_charset_info, curr_host,
- grant_table->host.hostname)))
+ my_strcasecmp(system_charset_info, curr_host, host)))
continue;
ulong table_access= grant_table->privs;
@@ -6004,7 +6036,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
if (!(table_access & GRANT_ACL))
is_grantable= "NO";
- strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
+ strxmov(buff, "'", user, "'@'", host, "'", NullS);
if (!test_access)
update_schema_privilege(table, buff, grant_table->db, grant_table->tname,
0, 0, STRING_WITH_LEN("USAGE"), is_grantable);
@@ -6046,16 +6078,17 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
for (index=0 ; index < column_priv_hash.records ; index++)
{
- const char *user, *is_grantable= "YES";
+ const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user= "";
+ if (!(host= grant_table->host.hostname))
+ host= "";
if (no_global_access &&
(strcmp(thd->security_ctx->priv_user, user) ||
- my_strcasecmp(system_charset_info, curr_host,
- grant_table->host.hostname)))
+ my_strcasecmp(system_charset_info, curr_host, host)))
continue;
ulong table_access= grant_table->cols;
@@ -6065,7 +6098,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
is_grantable= "NO";
ulong test_access= table_access & ~GRANT_ACL;
- strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
+ strxmov(buff, "'", user, "'@'", host, "'", NullS);
if (!test_access)
continue;
else
@@ -6154,20 +6187,21 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
}
/* table privileges */
+ rw_rdlock(&LOCK_grant);
if (grant->version != grant_version)
{
- rw_rdlock(&LOCK_grant);
grant->grant_table=
table_hash_search(sctx->host, sctx->ip, db,
sctx->priv_user,
table, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */
- rw_unlock(&LOCK_grant);
}
if (grant->grant_table != 0)
{
grant->privilege|= grant->grant_table->privs;
}
+ rw_unlock(&LOCK_grant);
+
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 802385a0f07..2298de7eeb5 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -25,7 +25,7 @@
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
-#ifdef __WIN__
+#ifdef __WIN__
#include <io.h>
#endif
@@ -879,7 +879,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
bool found=1;
/* Wait until all threads has closed all the tables we had locked */
DBUG_PRINT("info",
- ("Waiting for others threads to close their open tables"));
+ ("Waiting for other threads to close their open tables"));
while (found && ! thd->killed)
{
found=0;
@@ -890,6 +890,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
((table->s->version) < refresh_version && table->db_stat))
{
found=1;
+ DBUG_PRINT("signal", ("Waiting for COND_refresh"));
pthread_cond_wait(&COND_refresh,&LOCK_open);
break;
}
@@ -947,8 +948,13 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
for (; table ; table= table->next)
+ {
if (table->query_id == thd->query_id)
+ {
table->query_id= 0;
+ table->file->ha_reset();
+ }
+ }
}
@@ -1028,21 +1034,13 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
*/
ha_commit_stmt(thd);
- /* We are under simple LOCK TABLES so should not do anything else. */
- if (!prelocked_mode)
- DBUG_VOID_RETURN;
+ /* Ensure we are calling ha_reset() for all used tables */
+ mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
- if (!thd->lex->requires_prelocking())
- {
- /*
- If we are executing one of substatements we have to mark
- all tables which it used as free for reuse.
- */
- mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
+ /* We are under simple LOCK TABLES so should not do anything else. */
+ if (!prelocked_mode || !thd->lex->requires_prelocking())
DBUG_VOID_RETURN;
- }
- DBUG_ASSERT(prelocked_mode);
/*
We are in prelocked mode, so we have to leave it now with doing
implicit UNLOCK TABLES if need.
@@ -1096,7 +1094,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
found_old_table= 0;
while (thd->open_tables)
- found_old_table|=close_thread_table(thd, &thd->open_tables);
+ found_old_table|= close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0;
/* Free tables to hold down open files */
@@ -1125,6 +1123,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
DBUG_VOID_RETURN;
}
+
/* move one table to free list */
bool close_thread_table(THD *thd, TABLE **table_ptr)
@@ -1149,11 +1148,8 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
table->s->flush_version= flush_version;
table->file->extra(HA_EXTRA_FLUSH);
}
- else
- {
- // Free memory and reset for next loop
- table->file->ha_reset();
- }
+ // Free memory and reset for next loop
+ table->file->ha_reset();
table->in_use=0;
if (unused_tables)
{
@@ -1183,10 +1179,8 @@ static inline uint tmpkeyval(THD *thd, TABLE *table)
void close_temporary_tables(THD *thd)
{
- TABLE *next,
- *prev_table /* prev link is not maintained in TABLE's double-linked list */,
- *table;
- char *query= (gptr) 0, *end;
+ TABLE *next, *prev_table, *table;
+ char *query= 0, *end;
uint query_buf_size, max_names_len;
bool found_user_tables;
@@ -1289,7 +1283,7 @@ void close_temporary_tables(THD *thd)
table= next)
{
end_cur= strxmov(end_cur, "`", table->s->db.str, "`.`",
- table->s->table_name.str, "`,", NullS);
+ table->s->table_name.str, "`,", NullS);
next= table->next;
close_temporary(table, 1, 1);
}
@@ -1317,7 +1311,6 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
-
/*
Find table in list.
@@ -1685,6 +1678,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
thd->mysys_var->current_cond= cond;
proc_info=thd->proc_info;
thd->proc_info="Waiting for table";
+ DBUG_ENTER("wait_for_condition");
if (!thd->killed)
(void) pthread_cond_wait(cond, mutex);
@@ -1705,6 +1699,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
thd->mysys_var->current_cond= 0;
thd->proc_info= proc_info;
pthread_mutex_unlock(&thd->mysys_var->mutex);
+ DBUG_VOID_RETURN;
}
@@ -1983,6 +1978,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
if (table->s->version != refresh_version)
{
+ DBUG_PRINT("note",
+ ("Found table '%s.%s' with different refresh version",
+ table_list->db, table_list->table_name));
+
/*
Don't close tables if we are working with a log table or were
asked not to close the table explicitly
@@ -2090,6 +2089,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (table->timestamp_field)
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
+ table->clear_column_bitmaps();
DBUG_ASSERT(table->key_read == 0);
DBUG_RETURN(table);
}
@@ -2187,6 +2187,7 @@ static bool reopen_table(TABLE *table)
VOID(closefrm(table, 1)); // close file, free everything
*table= tmp;
+ table->default_column_bitmaps();
table->file->change_table_ptr(table, table->s);
DBUG_ASSERT(table->alias != 0);
@@ -3554,22 +3555,50 @@ Field *view_ref_found= (Field*) 0x2;
static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
{
- if (thd->set_query_id)
+ DBUG_ENTER("update_field_dependencies");
+ if (thd->mark_used_columns != MARK_COLUMNS_NONE)
{
- table->file->ha_set_bit_in_rw_set(field->fieldnr,
- (bool)(thd->set_query_id-1));
- if (field->query_id != thd->query_id)
+ MY_BITMAP *current_bitmap, *other_bitmap;
+
+ /*
+ We always want to register the used keys, as the column bitmap may have
+ been set for all fields (for example for view).
+ */
+
+ table->used_keys.intersect(field->part_of_key);
+ table->merge_keys.merge(field->part_of_key);
+
+ if (thd->mark_used_columns == MARK_COLUMNS_READ)
{
- if (table->get_fields_in_item_tree)
- field->flags|= GET_FIXED_FIELDS_FLAG;
- field->query_id= thd->query_id;
- table->used_fields++;
- table->used_keys.intersect(field->part_of_key);
+ current_bitmap= table->read_set;
+ other_bitmap= table->write_set;
}
else
- thd->dupp_field= field;
- } else if (table->get_fields_in_item_tree)
+ {
+ current_bitmap= table->write_set;
+ other_bitmap= table->read_set;
+ }
+
+ if (bitmap_fast_test_and_set(current_bitmap, field->field_index))
+ {
+ if (thd->mark_used_columns == MARK_COLUMNS_WRITE)
+ {
+ DBUG_PRINT("warning", ("Found duplicated field"));
+ thd->dup_field= field;
+ }
+ else
+ {
+ DBUG_PRINT("note", ("Field found before"));
+ }
+ DBUG_VOID_RETURN;
+ }
+ if (table->get_fields_in_item_tree)
+ field->flags|= GET_FIXED_FIELDS_FLAG;
+ table->used_fields++;
+ }
+ else if (table->get_fields_in_item_tree)
field->flags|= GET_FIXED_FIELDS_FLAG;
+ DBUG_VOID_RETURN;
}
@@ -3978,12 +4007,12 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
fld= WRONG_GRANT;
else
#endif
- if (thd->set_query_id)
+ if (thd->mark_used_columns != MARK_COLUMNS_NONE)
{
/*
- * get rw_set correct for this field so that the handler
- * knows that this field is involved in the query and gets
- * retrieved/updated
+ Get rw_set correct for this field so that the handler
+ knows that this field is involved in the query and gets
+ retrieved/updated
*/
Field *field_to_set= NULL;
if (fld == view_ref_found)
@@ -3991,13 +4020,22 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
Item *it= (*ref)->real_item();
if (it->type() == Item::FIELD_ITEM)
field_to_set= ((Item_field*)it)->field;
+ else
+ {
+ if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ it->walk(&Item::register_field_in_read_map, 1, (byte *) 0);
+ }
}
else
field_to_set= fld;
if (field_to_set)
- field_to_set->table->file->
- ha_set_bit_in_rw_set(field_to_set->fieldnr,
- (bool)(thd->set_query_id-1));
+ {
+ TABLE *table= field_to_set->table;
+ if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ bitmap_set_bit(table->read_set, field_to_set->field_index);
+ else
+ bitmap_set_bit(table->write_set, field_to_set->field_index);
+ }
}
}
DBUG_RETURN(fld);
@@ -4690,17 +4728,17 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
{
TABLE *table_1= nj_col_1->table_ref->table;
/* Mark field_1 used for table cache. */
- field_1->query_id= thd->query_id;
- table_1->file->ha_set_bit_in_read_set(field_1->fieldnr);
+ bitmap_set_bit(table_1->read_set, field_1->field_index);
table_1->used_keys.intersect(field_1->part_of_key);
+ table_1->merge_keys.merge(field_1->part_of_key);
}
if (field_2)
{
TABLE *table_2= nj_col_2->table_ref->table;
/* Mark field_2 used for table cache. */
- field_2->query_id= thd->query_id;
- table_2->file->ha_set_bit_in_read_set(field_2->fieldnr);
+ bitmap_set_bit(table_2->read_set, field_2->field_index);
table_2->used_keys.intersect(field_2->part_of_key);
+ table_2->merge_keys.merge(field_2->part_of_key);
}
if (using_fields != NULL)
@@ -5168,17 +5206,17 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
****************************************************************************/
bool setup_fields(THD *thd, Item **ref_pointer_array,
- List<Item> &fields, ulong set_query_id,
+ List<Item> &fields, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func)
{
reg2 Item *item;
- ulong save_set_query_id= thd->set_query_id;
+ enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
DBUG_ENTER("setup_fields");
- thd->set_query_id=set_query_id;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= mark_used_columns;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
if (allow_sum_func)
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
thd->where= THD::DEFAULT_WHERE;
@@ -5204,8 +5242,8 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
(item= *(it.ref()))->check_cols(1))
{
thd->lex->allow_sum_func= save_allow_sum_func;
- thd->set_query_id= save_set_query_id;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= save_mark_used_columns;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(TRUE); /* purecov: inspected */
}
if (ref)
@@ -5216,8 +5254,8 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->used_tables|= item->used_tables();
}
thd->lex->allow_sum_func= save_allow_sum_func;
- thd->set_query_id= save_set_query_id;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= save_mark_used_columns;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(test(thd->net.report_error));
}
@@ -5261,7 +5299,6 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
context name resolution contest to setup table list there
from_clause Top-level list of table references in the FROM clause
tables Table list (select_lex->table_list)
- conds Condition of current SELECT (can be changed by VIEW)
leaves List of join table leaves list (select_lex->leaf_tables)
refresh It is onle refresh for subquery
select_insert It is SELECT ... INSERT command
@@ -5283,7 +5320,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
bool setup_tables(THD *thd, Name_resolution_context *context,
List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
- Item **conds, TABLE_LIST **leaves, bool select_insert)
+ TABLE_LIST **leaves, bool select_insert)
{
uint tablenr= 0;
DBUG_ENTER("setup_tables");
@@ -5306,6 +5343,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
table_list= table_list->next_leaf, tablenr++)
{
TABLE *table= table_list->table;
+ table->pos_in_table_list= table_list;
if (first_select_table &&
table_list->top_table() == first_select_table)
{
@@ -5315,6 +5353,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
}
setup_table_map(table, table_list, tablenr);
table->used_keys= table->s->keys_for_keyread;
+ table->merge_keys.clear_all();
if (table_list->use_index)
{
key_map map;
@@ -5369,6 +5408,58 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
/*
+ prepare tables and check access for the view tables
+
+ SYNOPSIS
+ setup_tables_and_check_view_access()
+ thd Thread handler
+ context name resolution contest to setup table list there
+ from_clause Top-level list of table references in the FROM clause
+ tables Table list (select_lex->table_list)
+ conds Condition of current SELECT (can be changed by VIEW)
+ leaves List of join table leaves list (select_lex->leaf_tables)
+ refresh It is onle refresh for subquery
+ select_insert It is SELECT ... INSERT command
+ want_access what access is needed
+
+ NOTE
+ a wrapper for check_tables that will also check the resulting
+ table leaves list for access to all the tables that belong to a view
+
+ RETURN
+ FALSE ok; In this case *map will include the chosen index
+ TRUE error
+*/
+bool setup_tables_and_check_access(THD *thd,
+ Name_resolution_context *context,
+ List<TABLE_LIST> *from_clause,
+ TABLE_LIST *tables,
+ TABLE_LIST **leaves,
+ bool select_insert,
+ ulong want_access)
+{
+ TABLE_LIST *leaves_tmp= NULL;
+
+ if (setup_tables(thd, context, from_clause, tables,
+ &leaves_tmp, select_insert))
+ return TRUE;
+
+ *leaves= leaves_tmp;
+
+ for (; leaves_tmp; leaves_tmp= leaves_tmp->next_leaf)
+ {
+ if (leaves_tmp->belong_to_view &&
+ check_one_table_access(thd, want_access, leaves_tmp))
+ {
+ tables->hide_view_error(thd);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
Create a key_map from a list of index names
SYNOPSIS
@@ -5397,8 +5488,8 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
name->length(), 1)) <=
0)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
- table->s->table_name.str);
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
+ table->pos_in_table_list->alias);
map->set_all();
return 1;
}
@@ -5488,7 +5579,6 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
}
#endif
-
/*
Update the tables used in the query based on the referenced fields. For
views and natural joins this update is performed inside the loop below.
@@ -5554,18 +5644,13 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if ((field= field_iterator.field()))
{
- /*
- Mark if field used before in this select.
- Used by 'insert' to verify if a field name is used twice.
- */
- if (field->query_id == thd->query_id)
- thd->dupp_field= field;
- field->query_id= thd->query_id;
- field->table->file->ha_set_bit_in_read_set(field->fieldnr);
-
+ /* Mark fields as used to allow storage engine to optimze access */
+ bitmap_set_bit(field->table->read_set, field->field_index);
if (table)
+ {
table->used_keys.intersect(field->part_of_key);
-
+ table->merge_keys.merge(field->part_of_key);
+ }
if (tables->is_natural_join)
{
TABLE *field_table;
@@ -5582,16 +5667,13 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
{
thd->used_tables|= field_table->map;
field_table->used_keys.intersect(field->part_of_key);
+ field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
}
}
}
else
- {
thd->used_tables|= item->used_tables();
- item->walk(&Item::reset_query_id_processor,
- (byte *)(&thd->query_id));
- }
}
/*
In case of stored tables, all fields are considered as used,
@@ -5600,10 +5682,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
For NATURAL joins, used_tables is updated in the IF above.
*/
if (table)
- {
table->used_fields= table->s->fields;
- table->file->ha_set_all_bits_in_read_set();
- }
}
if (found)
DBUG_RETURN(FALSE);
@@ -5662,8 +5741,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
arena->is_conventional())
arena= 0; // For easier test
- thd->set_query_id=1;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= MARK_COLUMNS_READ;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
select_lex->cond_count= 0;
for (table= tables; table; table= table->next_local)
@@ -5918,7 +5997,7 @@ static void mysql_rm_tmp_tables(void)
if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length))
{
- sprintf(filePath,"%s%s",tmpdir,file->name);
+ sprintf(filePath,"%s%c%s",tmpdir,FN_LIBCHAR,file->name);
VOID(my_delete(filePath,MYF(MY_WME)));
}
}
@@ -6004,6 +6083,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
TABLE_SHARE *share;
bool result= 0, signalled= 0;
DBUG_ENTER("remove_table_from_cache");
+ DBUG_PRINT("enter", ("Table: '%s.%s' flags: %u", db, table_name, flags));
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
for (;;)
@@ -6030,7 +6110,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
DBUG_PRINT("info", ("Table was in use by other thread"));
in_use->some_tables_deleted=1;
if (table->db_stat)
+ {
+ DBUG_PRINT("info", ("Found another active instance of the table"));
result=1;
+ }
/* Kill delayed insert threads */
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
@@ -6085,6 +6168,12 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
{
+ /*
+ Signal any thread waiting for tables to be freed to
+ reopen their tables
+ */
+ (void) pthread_cond_broadcast(&COND_refresh);
+ DBUG_PRINT("info", ("Waiting for refresh signal"));
if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed)
{
dropping_tables++;
@@ -6164,7 +6253,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
alias alias for table
db database
table_name name of table
- db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
+ db_stat open flags (for example ->OPEN_KEYFILE|HA_OPEN_RNDFILE..)
can be 0 (example in ha_example_table)
prgflag READ_ALL etc..
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index 35c501ede56..3a7fa4b661a 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -66,6 +66,7 @@ public:
my_bool is_clear_all() const { return bitmap_is_clear_all(&map); }
my_bool is_set_all() const { return bitmap_is_set_all(&map); }
my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); }
+ my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, map2.map); }
my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); }
char *print(char *buf) const
{
@@ -132,6 +133,7 @@ public:
my_bool is_clear_all() const { return map == (ulonglong)0; }
my_bool is_set_all() const { return map == ~(ulonglong)0; }
my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
+ my_bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; }
my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
ulonglong to_ulonglong() const { return map; }
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4bc89bfe916..0ede042da17 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -186,6 +186,11 @@ const char *thd_proc_info(THD *thd, const char *info)
return old_info;
}
+void **thd_ha_data(const THD *thd, const struct handlerton *hton)
+{
+ return (void **) thd->ha_data + hton->slot;
+}
+
/*
Pass nominal parameters to Statement constructor only to ensure that
@@ -223,7 +228,7 @@ THD::THD()
hash_clear(&handler_tables_hash);
tmp_table=0;
used_tables=0;
- cuted_fields= sent_row_count= 0L;
+ cuted_fields= sent_row_count= row_count= 0L;
limit_found_rows= 0;
statement_id_counter= 0UL;
#ifdef ERROR_INJECT_SUPPORT
@@ -243,6 +248,7 @@ THD::THD()
bzero(ha_data, sizeof(ha_data));
mysys_var=0;
binlog_evt_union.do_union= FALSE;
+ enable_slow_log= 0;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
#endif
@@ -253,7 +259,8 @@ THD::THD()
net.last_error[0]=0; // If error on boot
net.query_cache_query=0; // If error on boot
ull=0;
- system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
+ system_thread= NON_SYSTEM_THREAD;
+ cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
#ifdef HAVE_ROW_BASED_REPLICATION
transaction.m_pending_rows_event= 0;
@@ -512,6 +519,8 @@ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
void THD::awake(THD::killed_state state_to_set)
{
+ DBUG_ENTER("THD::awake");
+ DBUG_PRINT("enter", ("this=0x%lx", this));
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
@@ -555,6 +564,7 @@ void THD::awake(THD::killed_state state_to_set)
}
pthread_mutex_unlock(&mysys_var->mutex);
}
+ DBUG_VOID_RETURN;
}
/*
@@ -1637,7 +1647,7 @@ Statement::Statement(enum enum_state state_arg, ulong id_arg,
ulong alloc_block_size, ulong prealloc_size)
:Query_arena(&main_mem_root, state_arg),
id(id_arg),
- set_query_id(1),
+ mark_used_columns(MARK_COLUMNS_READ),
lex(&main_lex),
query(0),
query_length(0),
@@ -1657,7 +1667,7 @@ Query_arena::Type Statement::type() const
void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
- set_query_id= stmt->set_query_id;
+ mark_used_columns= stmt->mark_used_columns;
lex= stmt->lex;
query= stmt->query;
query_length= stmt->query_length;
@@ -2031,6 +2041,13 @@ void Security_context::skip_grants()
}
+bool Security_context::set_user(char *user_arg)
+{
+ safeFree(user);
+ user= my_strdup(user_arg, MYF(0));
+ return user == 0;
+}
+
/****************************************************************************
Handling of open and locked tables states.
@@ -2433,6 +2450,7 @@ field_type_name(enum_field_types type)
return "Unknown";
}
+
my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const
{
my_size_t length= 0;
@@ -2449,53 +2467,52 @@ my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const
return length;
}
+
my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data,
const byte *record) const
{
- Field **p_field= table->field, *field= *p_field;
+ Field **p_field= table->field, *field;
int n_null_bytes= table->s->null_bytes;
- my_ptrdiff_t const offset= record - (byte*) table->record[0];
-
+ byte *ptr;
+ uint i;
+ my_ptrdiff_t const offset= (my_ptrdiff_t) (record - (byte*)
+ table->record[0]);
memcpy(row_data, record, n_null_bytes);
- byte *ptr= row_data+n_null_bytes;
+ ptr= row_data+n_null_bytes;
- for (int i= 0 ; field ; i++, p_field++, field= *p_field)
+ for (i= 0 ; (field= *p_field) ; i++, p_field++)
{
if (bitmap_is_set(cols,i))
ptr= (byte*)field->pack((char *) ptr, field->ptr + offset);
}
-
- /*
- my_ptrdiff_t is signed, size_t is unsigned. Assert that the
- conversion will work correctly.
- */
- DBUG_ASSERT(ptr - row_data >= 0);
- return (static_cast<size_t>(ptr - row_data));
+ return (static_cast<my_size_t>(ptr - row_data));
}
+
int THD::binlog_write_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, my_size_t colcnt,
byte const *record)
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
- /*
- Pack records into format for transfer. We are allocating more
- memory than needed, but that doesn't matter.
+ /*
+ Pack records into format for transfer. We are allocating more
+ memory than needed, but that doesn't matter.
*/
bool error= 0;
byte *row_data= table->write_row_record;
my_size_t const max_len= max_row_length(table, record);
-
- /*
- * Allocate room for a row (if needed)
- */
+ my_size_t len;
+ Rows_log_event *ev;
+
+ /* Allocate room for a row (if needed) */
if (!row_data)
{
if (!table->s->blob_fields)
{
/* multiply max_len by 2 so it can be used for update_row as well */
- table->write_row_record= (byte *) alloc_root(&table->mem_root, 2*max_len);
+ table->write_row_record= (byte *) alloc_root(&table->mem_root,
+ 2*max_len);
if (!table->write_row_record)
return HA_ERR_OUT_OF_MEM;
row_data= table->write_row_record;
@@ -2503,12 +2520,11 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
else if (unlikely(!(row_data= (byte *) my_malloc(max_len, MYF(MY_WME)))))
return HA_ERR_OUT_OF_MEM;
}
- my_size_t const len= pack_row(table, cols, row_data, record);
+ len= pack_row(table, cols, row_data, record);
- Rows_log_event* const ev=
- binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
- len, is_trans,
- static_cast<Write_rows_log_event*>(0));
+ ev= binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
+ len, is_trans,
+ static_cast<Write_rows_log_event*>(0));
/* add_row_data copies row_data to internal buffer */
error= likely(ev != 0) ? ev->add_row_data(row_data,len) : HA_ERR_OUT_OF_MEM ;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 04095ff9acd..03a8439db58 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -37,9 +37,10 @@ enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
-
-enum enum_check_fields { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN,
- CHECK_FIELD_ERROR_FOR_NULL };
+enum enum_check_fields
+{ CHECK_FIELD_IGNORE, CHECK_FIELD_WARN, CHECK_FIELD_ERROR_FOR_NULL };
+enum enum_mark_columns
+{ MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
extern char internal_table_name[2];
extern const char **errmesg;
@@ -465,17 +466,17 @@ public:
ulong id;
/*
- - if set_query_id=1, we set field->query_id for all fields. In that case
- field list can not contain duplicates.
- 0: Means query_id is not set and no indicator to handler of fields used
- is set
- 1: Means query_id is set for fields in list and bit in read set is set
- to inform handler of that field is to be read
- 2: Means query is set for fields in list and bit is set in update set
- to inform handler that it needs to update this field in write_row
- and update_row
+ MARK_COLUMNS_NONE: Means mark_used_colums is not set and no indicator to
+ handler of fields used is set
+ MARK_COLUMNS_READ: Means a bit in read set is set to inform handler
+ that the field is to be read. If field list contains
+ duplicates, then thd->dup_field is set to point
+ to the last found duplicate.
+ MARK_COLUMNS_WRITE: Means a bit is set in write set to inform handler
+ that it needs to update this field in write_row
+ and update_row.
*/
- ulong set_query_id;
+ enum enum_mark_columns mark_used_columns;
LEX_STRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
@@ -629,6 +630,8 @@ public:
{
return (*priv_host ? priv_host : (char *)"%");
}
+
+ bool set_user(char *user_arg);
};
@@ -770,6 +773,19 @@ public:
};
+/* Flags for the THD::system_thread variable */
+enum enum_thread_type
+{
+ NON_SYSTEM_THREAD= 0,
+ SYSTEM_THREAD_DELAYED_INSERT= 1,
+ SYSTEM_THREAD_SLAVE_IO= 2,
+ SYSTEM_THREAD_SLAVE_SQL= 4,
+ SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
+ SYSTEM_THREAD_EVENT_SCHEDULER= 16,
+ SYSTEM_THREAD_EVENT_WORKER= 32
+};
+
+
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1012,7 +1028,7 @@ public:
#endif
}
} transaction;
- Field *dupp_field;
+ Field *dup_field;
#ifndef __WIN__
sigset_t signals,block_signals;
#endif
@@ -1103,7 +1119,8 @@ public:
long dbug_thread_id;
pthread_t real_id;
uint tmp_table, global_read_lock;
- uint server_status,open_options,system_thread;
+ uint server_status,open_options;
+ enum enum_thread_type system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
@@ -1392,7 +1409,8 @@ public:
}
inline void reset_current_stmt_binlog_row_based()
{
- current_stmt_binlog_row_based= test(variables.binlog_format == BINLOG_FORMAT_ROW);
+ current_stmt_binlog_row_based= test(variables.binlog_format ==
+ BINLOG_FORMAT_ROW);
}
#endif /*HAVE_ROW_BASED_REPLICATION*/
};
@@ -1404,11 +1422,6 @@ public:
#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
-/* Flags for the THD::system_thread (bitmap) variable */
-#define SYSTEM_THREAD_DELAYED_INSERT 1
-#define SYSTEM_THREAD_SLAVE_IO 2
-#define SYSTEM_THREAD_SLAVE_SQL 4
-#define SYSTEM_THREAD_NDBCLUSTER_BINLOG 8
/*
Used to hold information about file and file structure in exchainge
@@ -1559,6 +1572,7 @@ class select_insert :public select_result_interceptor {
int prepare2(void);
bool send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
+ virtual bool can_rollback_data() { return 0; }
void send_error(uint errcode,const char *err);
bool send_eof();
/* not implemented: select_insert is never re-used in prepared statements */
@@ -1580,17 +1594,19 @@ public:
List<create_field> &fields_par,
List<Key> &keys_par,
List<Item> &select_fields,enum_duplicates duplic, bool ignore)
- :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table),
- extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par),
+ :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore),
+ create_table(table), extra_fields(&fields_par),keys(&keys_par),
+ create_info(create_info_par),
lock(0)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
-
void binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
void abort();
+ virtual bool can_rollback_data() { return 1; }
+
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
THD *get_thd(void) { return thd; }
};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3d035359b6f..11c892fee44 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -538,16 +538,27 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
}
-
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- /* do not create database if another thread is holding read lock */
+ /*
+ Do not create database if another thread is holding read lock.
+ Wait for global read lock before acquiring LOCK_mysql_create_db.
+ After wait_if_global_read_lock() we have protection against another
+ global read lock. If we would acquire LOCK_mysql_create_db first,
+ another thread could step in and get the global read lock before we
+ reach wait_if_global_read_lock(). If this thread tries the same as we
+ (admin a db), it would then go and wait on LOCK_mysql_create_db...
+ Furthermore wait_if_global_read_lock() checks if the current thread
+ has the global read lock and refuses the operation with
+ ER_CANT_UPDATE_WITH_READLOCK if applicable.
+ */
if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
goto exit2;
}
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
/* Check directory */
path_len= build_table_filename(path, sizeof(path), db, "", "");
path[path_len-1]= 0; // Remove last '/' from path
@@ -655,9 +666,9 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
}
exit:
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
start_waiting_global_read_lock(thd);
exit2:
- VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
DBUG_RETURN(error);
}
@@ -671,12 +682,23 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
int error= 0;
DBUG_ENTER("mysql_alter_db");
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
-
- /* do not alter database if another thread is holding read lock */
+ /*
+ Do not alter database if another thread is holding read lock.
+ Wait for global read lock before acquiring LOCK_mysql_create_db.
+ After wait_if_global_read_lock() we have protection against another
+ global read lock. If we would acquire LOCK_mysql_create_db first,
+ another thread could step in and get the global read lock before we
+ reach wait_if_global_read_lock(). If this thread tries the same as we
+ (admin a db), it would then go and wait on LOCK_mysql_create_db...
+ Furthermore wait_if_global_read_lock() checks if the current thread
+ has the global read lock and refuses the operation with
+ ER_CANT_UPDATE_WITH_READLOCK if applicable.
+ */
if ((error=wait_if_global_read_lock(thd,0,1)))
goto exit2;
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
/*
Recreate db options file: /dbpath/.db.opt
We pass MY_DB_OPT_FILE as "extension" to avoid
@@ -721,9 +743,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
send_ok(thd, result);
exit:
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
start_waiting_global_read_lock(thd);
exit2:
- VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
DBUG_RETURN(error);
}
@@ -755,15 +777,26 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
TABLE_LIST* dropped_tables= 0;
DBUG_ENTER("mysql_rm_db");
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
-
- /* do not drop database if another thread is holding read lock */
+ /*
+ Do not drop database if another thread is holding read lock.
+ Wait for global read lock before acquiring LOCK_mysql_create_db.
+ After wait_if_global_read_lock() we have protection against another
+ global read lock. If we would acquire LOCK_mysql_create_db first,
+ another thread could step in and get the global read lock before we
+ reach wait_if_global_read_lock(). If this thread tries the same as we
+ (admin a db), it would then go and wait on LOCK_mysql_create_db...
+ Furthermore wait_if_global_read_lock() checks if the current thread
+ has the global read lock and refuses the operation with
+ ER_CANT_UPDATE_WITH_READLOCK if applicable.
+ */
if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
goto exit2;
}
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
length= build_table_filename(path, sizeof(path), db, "", "");
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
@@ -871,8 +904,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
- (void)evex_drop_db_events(thd, db); /* QQ Ignore errors for now */
- start_waiting_global_read_lock(thd);
+ error= Events::drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently change the
client's selected database to nothing (to have an empty SELECT DATABASE()
@@ -901,9 +933,9 @@ exit:
thd->db= 0;
thd->db_length= 0;
}
-exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
-
+ start_waiting_global_read_lock(thd);
+exit2:
DBUG_RETURN(error);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 44b0fe1a2f1..a7a50611a02 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -80,9 +80,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
!(table->triggers && table->triggers->has_delete_triggers()))
{
- /* Update the table->file->records number */
+ /* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- ha_rows const maybe_deleted= table->file->records;
+ ha_rows const maybe_deleted= table->file->stats.records;
/*
If all rows shall be deleted, we (almost) always log this
statement-based (see [binlog], below), so we set this flag and
@@ -113,7 +113,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(0);
}
#endif
- /* Update the table->file->records number */
+ /* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
table->used_keys.clear_all();
@@ -184,7 +184,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
&length)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
- select, HA_POS_ERROR,
+ select, HA_POS_ERROR, 1,
&examined_rows))
== HA_POS_ERROR)
{
@@ -226,6 +226,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (ha_delete_all_rows)
thd->options&= ~static_cast<ulonglong>(OPTION_BIN_LOG);
+ table->mark_columns_needed_for_delete();
+
while (!(error=info.read_record(&info)) && !thd->killed &&
!thd->net.report_error)
{
@@ -285,7 +287,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
thd->proc_info= "end";
end_read_record(&info);
- free_io_cache(table); // Will not do any harm
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
@@ -394,10 +395,11 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_ENTER("mysql_prepare_delete");
thd->lex->allow_sum_func= 0;
- if (setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- table_list, conds, &select_lex->leaf_tables,
- FALSE) ||
+ if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
+ table_list,
+ &select_lex->leaf_tables, FALSE,
+ DELETE_ACL) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
@@ -456,10 +458,11 @@ bool mysql_multi_delete_prepare(THD *thd)
lex->query_tables also point on local list of DELETE SELECT_LEX
*/
- if (setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- lex->query_tables, &lex->select_lex.where,
- &lex->select_lex.leaf_tables, FALSE))
+ if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
+ lex->query_tables,
+ &lex->select_lex.leaf_tables, FALSE,
+ DELETE_ACL))
DBUG_RETURN(TRUE);
@@ -565,6 +568,8 @@ multi_delete::initialize_tables(JOIN *join)
transactional_tables= 1;
else
normal_tables= 1;
+ tbl->prepare_for_position();
+ tbl->mark_columns_needed_for_delete();
}
else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
walk == delete_tables)
@@ -604,7 +609,6 @@ multi_delete::~multi_delete()
table_being_deleted= table_being_deleted->next_local)
{
TABLE *table= table_being_deleted->table;
- free_io_cache(table); // Alloced by unique
table->no_keyread=0;
}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 08388dee516..98483ce2de6 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -24,7 +24,7 @@ bool mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd, 0, values, 0, 0, 0))
+ if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, 0))
DBUG_RETURN(TRUE);
while ((value = li++))
value->val_int();
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 223b50be744..b5cac24d894 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -40,3 +40,5 @@ void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
uint code, const char *format, ...);
void mysql_reset_errors(THD *thd, bool force);
bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
+
+extern LEX_STRING warning_level_names[];
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 18b63ba49a3..bf035401bea 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -188,13 +188,13 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* for now HANDLER can be used only for real TABLES */
tables->required_type= FRMTYPE_TABLE;
error= open_tables(thd, &tables, &counter, 0);
-
HANDLER_TABLES_HACK(thd);
+
if (error)
goto err;
/* There can be only one table in '*tables'. */
- if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
+ if (! (tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
{
if (! reopen)
my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
@@ -421,6 +421,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (!lock)
goto err0; // mysql_lock_tables() printed error message already
+ // Always read all columns
+ tables->table->read_set= &tables->table->s->all_set;
+
if (cond)
{
if (table->query_id != thd->query_id)
@@ -514,6 +517,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
+ my_bitmap_map *old_map;
// 'item' can be changed by fix_fields() call
if ((!item->fixed &&
item->fix_fields(thd, it_ke.ref())) ||
@@ -524,16 +528,19 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ");
goto err;
}
+ old_map= dbug_tmp_use_all_columns(table, table->write_set);
(void) item->save_in_field(key_part->field, 1);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
key_len+=key_part->store_length;
}
+
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
goto err;
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno, 1);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->index_read(table->record[0],
- key,key_len,ha_rkey_mode);
+ key,key_len,ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode];
break;
}
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index ea9bca57cc6..69d21f8b7bb 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -94,6 +94,11 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
0, REPORT_ALL_ERRORS, 1,
TRUE)))
DBUG_RETURN(1);
+ bitmap_set_bit(find_fields->field->table->read_set,
+ find_fields->field->field_index);
+ /* To make life easier when setting values in keys */
+ bitmap_set_bit(find_fields->field->table->write_set,
+ find_fields->field->field_index);
}
DBUG_RETURN(0);
}
@@ -272,7 +277,6 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
int count= 0;
int iindex_topic, iindex_relations;
Field *rtopic_id, *rkey_id;
-
DBUG_ENTER("get_topics_for_keyword");
if ((iindex_topic= find_type((char*) primary_key_name,
@@ -292,8 +296,9 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
rkey_id->store((longlong) key_id, TRUE);
rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
- (byte *)buff, rkey_id->pack_length(),
- HA_READ_KEY_EXACT);
+ (byte *) buff,
+ rkey_id->pack_length(),
+ HA_READ_KEY_EXACT);
for ( ;
!key_res && key_id == (int16) rkey_id->val_int() ;
@@ -653,13 +658,15 @@ bool mysqld_help(THD *thd, const char *mask)
if (open_and_lock_tables(thd, tables))
goto error;
+
/*
Init tables and fields to be usable from items
tables do not contain VIEWs => we can pass 0 as conds
*/
- setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- tables, 0, &leaves, FALSE);
+ if (setup_tables(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
+ tables, &leaves, FALSE))
+ goto error;
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
goto error;
@@ -681,10 +688,12 @@ bool mysqld_help(THD *thd, const char *mask)
int key_id;
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[3].table,
- used_fields[help_keyword_name].field,&error)))
+ used_fields[help_keyword_name].field,
+ &error)))
goto error;
- count_topics=search_keyword(thd,tables[3].table,used_fields,select,&key_id);
+ count_topics= search_keyword(thd,tables[3].table, used_fields, select,
+ &key_id);
delete select;
count_topics= (count_topics != 1) ? 0 :
get_topics_for_keyword(thd,tables[0].table,tables[2].table,
@@ -698,7 +707,8 @@ bool mysqld_help(THD *thd, const char *mask)
Field *cat_cat_id= used_fields[help_category_parent_category_id].field;
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
- used_fields[help_category_name].field,&error)))
+ used_fields[help_category_name].field,
+ &error)))
goto error;
count_categories= search_categories(thd, tables[1].table, used_fields,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 675fb256b32..0dae2b8f37b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -108,7 +108,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
No fields are provided so all fields must be provided in the values.
Thus we set all bits in the write set.
*/
- table->file->ha_set_all_bits_in_write_set();
+ bitmap_set_all(table->write_set);
}
else
{ // Part field list
@@ -123,7 +123,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
return -1;
}
- thd->dupp_field=0;
+ thd->dup_field= 0;
select_lex->no_wrap_view_item= TRUE;
/* Save the state of the current name resolution context. */
@@ -135,11 +135,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- /*
- Indicate fields in list is to be updated by setting set_query_id
- parameter to 2. This sets the bit in the write_set for each field.
- */
- res= setup_fields(thd, 0, fields, 2, 0, 0);
+ res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -167,16 +163,27 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
table_list->table= table= tbl->table;
}
- if (check_unique && thd->dupp_field)
+ if (check_unique && thd->dup_field)
{
- my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
+ my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dup_field->field_name);
return -1;
}
- if (table->timestamp_field && // Don't set timestamp if used
- table->timestamp_field->query_id == thd->query_id)
- clear_timestamp_auto_bits(table->timestamp_field_type,
- TIMESTAMP_AUTO_SET_ON_INSERT);
+ if (table->timestamp_field) // Don't automaticly set timestamp if used
+ {
+ if (bitmap_is_set(table->write_set,
+ table->timestamp_field->field_index))
+ clear_timestamp_auto_bits(table->timestamp_field_type,
+ TIMESTAMP_AUTO_SET_ON_INSERT);
+ else
+ {
+ bitmap_set_bit(table->write_set,
+ table->timestamp_field->field_index);
+ }
+ }
}
+ if (table->found_next_number_field)
+ table->mark_auto_increment_column();
+ table->mark_columns_needed_for_insert();
// For the values we need select_priv
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
@@ -217,40 +224,33 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List<Item> &update_fields)
{
TABLE *table= insert_table_list->table;
- query_id_t timestamp_query_id;
- LINT_INIT(timestamp_query_id);
+ my_bool timestamp_mark;
- /*
- Change the query_id for the timestamp column so that we can
- check if this is modified directly.
- */
if (table->timestamp_field)
{
- timestamp_query_id= table->timestamp_field->query_id;
- table->timestamp_field->query_id= thd->query_id - 1;
+ /*
+ Unmark the timestamp field so that we can check if this is modified
+ by update_fields
+ */
+ timestamp_mark= bitmap_test_and_clear(table->write_set,
+ table->timestamp_field->field_index);
}
- /*
- Check the fields we are going to modify. This will set the query_id
- of all used fields to the threads query_id. It will also set all
- fields into the write set of this table.
- */
- if (setup_fields(thd, 0, update_fields, 2, 0, 0))
+ /* Check the fields we are going to modify */
+ if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
return -1;
if (table->timestamp_field)
{
/* Don't set timestamp column if this is modified. */
- if (table->timestamp_field->query_id == thd->query_id)
+ if (bitmap_is_set(table->write_set,
+ table->timestamp_field->field_index))
clear_timestamp_auto_bits(table->timestamp_field_type,
TIMESTAMP_AUTO_SET_ON_UPDATE);
- else
- {
- table->timestamp_field->query_id= timestamp_query_id;
- table->file->ha_set_bit_in_write_set(table->timestamp_field->fieldnr);
- }
+ if (timestamp_mark)
+ bitmap_set_bit(table->write_set,
+ table->timestamp_field->field_index);
}
-
return 0;
}
@@ -269,8 +269,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
By default, both logs are enabled (this won't cause problems if the server
runs without --log-update or --log-bin).
*/
- bool log_on= (thd->options & OPTION_BIN_LOG) ||
- (!(thd->security_ctx->master_access & SUPER_ACL));
+ bool log_on= ((thd->options & OPTION_BIN_LOG) ||
+ (!(thd->security_ctx->master_access & SUPER_ACL)));
bool transactional_table, joins_freed= FALSE;
bool changed;
uint value_count;
@@ -380,7 +380,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
- if (setup_fields(thd, 0, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
goto abort;
}
its.rewind ();
@@ -428,7 +428,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
the code to make the call of end_bulk_insert() below safe.
*/
if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
- table->file->start_bulk_insert(values_list.elements);
+ table->file->ha_start_bulk_insert(values_list.elements);
thd->no_trans_update= 0;
thd->abort_on_warning= (!ignore &&
@@ -553,7 +553,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
else
#endif
{
- if (!thd->prelocked_mode && table->file->end_bulk_insert() && !error)
+ if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
{
table->file->print_error(my_errno,MYF(0));
error=1;
@@ -644,6 +644,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->row_count_func= info.copied+info.deleted+info.updated;
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
+ if (table != NULL)
+ table->file->release_auto_increment();
thd->abort_on_warning= 0;
DBUG_RETURN(FALSE);
@@ -652,6 +654,8 @@ abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
#endif
+ if (table != NULL)
+ table->file->release_auto_increment();
if (!joins_freed)
free_underlaid_joins(thd, &thd->lex->select_lex);
thd->abort_on_warning= 0;
@@ -753,16 +757,17 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
*/
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
- List<Item> &fields, COND **where,
+ List<Item> &fields,
bool select_insert)
{
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert_check_table");
- if (setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- table_list, where, &thd->lex->select_lex.leaf_tables,
- select_insert))
+ if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
+ table_list,
+ &thd->lex->select_lex.leaf_tables,
+ select_insert, INSERT_ACL))
DBUG_RETURN(TRUE);
if (insert_into_view && !fields.elements)
@@ -851,8 +856,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
}
- if (mysql_prepare_insert_check_table(thd, table_list, fields, where,
- select_insert))
+ if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert))
DBUG_RETURN(TRUE);
/* Save the state of the current name resolution context. */
@@ -869,7 +873,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (values &&
!(res= check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view) ||
- setup_fields(thd, 0, *values, 0, 0, 0)) &&
+ setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) &&
duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
@@ -887,7 +891,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
next_name_resolution_table= ctx_state.save_next_local;
}
if (!res)
- res= setup_fields(thd, 0, update_values, 1, 0, 0);
+ res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
/* Restore the current context. */
@@ -912,7 +916,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
select_lex->first_execution= 0;
}
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
- table->file->ha_retrieve_all_pk();
+ table->prepare_for_position();
DBUG_RETURN(FALSE);
}
@@ -959,9 +963,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
{
int error, trg_error= 0;
char *key=0;
+ MY_BITMAP *save_read_set, *save_write_set;
DBUG_ENTER("write_record");
info->records++;
+ save_read_set= table->read_set;
+ save_write_set= table->write_set;
if (info->handle_duplicates == DUP_REPLACE ||
info->handle_duplicates == DUP_UPDATE)
@@ -971,12 +978,14 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
uint key_nr;
if (error != HA_WRITE_SKIP)
goto err;
- table->file->restore_auto_increment();
+ table->file->restore_auto_increment(); // it's too early here! BUG#20188
if ((int) (key_nr = table->file->get_dup_key(error)) < 0)
{
error=HA_WRITE_SKIP; /* Database can't find key */
goto err;
}
+ /* Read all columns for the row we are going to replace */
+ table->use_all_columns();
/*
Don't allow REPLACE to replace a row when a auto_increment column
was used. This ensures that we don't get a problem when the
@@ -987,9 +996,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
key_nr == table->s->next_number_index &&
table->file->auto_increment_column_changed)
goto err;
- if (table->file->table_flags() & HA_DUPP_POS)
+ if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
{
- if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
+ if (table->file->rnd_pos(table->record[1],table->file->dup_ref))
goto err;
}
else
@@ -1050,7 +1059,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
thd->clear_next_insert_id= 0;
thd->next_insert_id= 0;
}
- if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
+ if ((error=table->file->ha_update_row(table->record[1],
+ table->record[0])))
{
if ((error == HA_ERR_FOUND_DUPP_KEY) && info->ignore)
goto ok_or_after_trg_err;
@@ -1127,6 +1137,13 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_AFTER, TRUE));
+ /*
+ Restore column maps if they where replaced during an duplicate key
+ problem.
+ */
+ if (table->read_set != save_read_set ||
+ table->write_set != save_write_set)
+ table->column_bitmaps_set(save_read_set, save_write_set);
}
else if ((error=table->file->ha_write_row(table->record[0])))
{
@@ -1160,6 +1177,7 @@ err:
before_trg_err:
if (key)
my_safe_afree(key, table->s->max_unique_length, MAX_KEY_LENGTH);
+ table->column_bitmaps_set(save_read_set, save_write_set);
DBUG_RETURN(1);
}
@@ -1172,9 +1190,11 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list)
{
int err= 0;
+ MY_BITMAP *write_set= entry->write_set;
+
for (Field **field=entry->field ; *field ; field++)
{
- if ((*field)->query_id != thd->query_id &&
+ if (!bitmap_is_set(write_set, (*field)->field_index) &&
((*field)->flags & NO_DEFAULT_VALUE_FLAG) &&
((*field)->real_type() != FIELD_TYPE_ENUM))
{
@@ -1506,6 +1526,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
Field **field,**org_field, *found_next_number_field;
TABLE *copy;
TABLE_SHARE *share= table->s;
+ byte *bitmap;
/* First request insert thread to get a lock */
status=1;
@@ -1532,14 +1553,16 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
client_thd->proc_info="allocating local table";
copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
(share->fields+1)*sizeof(Field**)+
- share->reclength);
+ share->reclength +
+ share->column_bitmap_size*2);
if (!copy)
goto error;
*copy= *table;
/* We don't need to change the file handler here */
- field=copy->field=(Field**) (copy+1);
- copy->record[0]=(byte*) (field+share->fields+1);
+ field= copy->field= (Field**) (copy+1);
+ bitmap= (byte*) (field+share->fields+1);
+ copy->record[0]= (bitmap+ share->column_bitmap_size*2);
memcpy((char*) copy->record[0],(char*) table->record[0],share->reclength);
/* Make a copy of all fields */
@@ -1568,13 +1591,21 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
copy->timestamp_field_type= copy->timestamp_field->get_auto_set_type();
}
-
/* Adjust in_use for pointing to client thread */
copy->in_use= client_thd;
/* Adjust lock_count. This table object is not part of a lock. */
copy->lock_count= 0;
+ /* Adjust bitmaps */
+ copy->def_read_set.bitmap= (my_bitmap_map*) bitmap;
+ copy->def_write_set.bitmap= ((my_bitmap_map*)
+ (bitmap + share->column_bitmap_size));
+ copy->tmp_set.bitmap= 0; // To catch errors
+ bzero((char*) bitmap, share->column_bitmap_size*2);
+ copy->read_set= &copy->def_read_set;
+ copy->write_set= &copy->def_write_set;
+
return copy;
/* Got fatal error */
@@ -1742,7 +1773,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->fatal_error(); // Abort waiting inserts
goto err;
}
- if (!(di->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
+ if (!(di->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
thd->fatal_error();
my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.table_name);
@@ -1952,6 +1983,7 @@ bool delayed_insert::handle_inserts(void)
pthread_mutex_unlock(&mutex);
table->next_number_field=table->found_next_number_field;
+ table->use_all_columns();
thd.proc_info="upgrading lock";
if (thr_upgrade_write_delay_lock(*thd.lock->locks))
@@ -2058,7 +2090,6 @@ bool delayed_insert::handle_inserts(void)
}
thd.proc_info=0;
- table->next_number_field=0;
pthread_mutex_unlock(&mutex);
/* After releasing the mutex, to prevent deadlocks. */
@@ -2181,7 +2212,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->current_select= &lex->select_lex;
res= check_insert_fields(thd, table_list, *fields, values,
!insert_into_view) ||
- setup_fields(thd, 0, values, 0, 0, 0);
+ setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
if (info.handle_duplicates == DUP_UPDATE)
{
@@ -2211,7 +2242,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
context->first_name_resolution_table->
next_name_resolution_table= ctx_state.save_next_local;
}
- res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
+ res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ,
+ 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -2248,7 +2280,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
We won't start bulk inserts at all if this statement uses functions or
should invoke triggers since they may access to the same table too.
*/
- table->file->start_bulk_insert((ha_rows) 0);
+ table->file->ha_start_bulk_insert((ha_rows) 0);
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
@@ -2264,16 +2296,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
check_that_all_fields_are_given_values(thd, table, table_list)) ||
table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd));
-
- /*
- For non-transactional non-temporary tables, we set the
- OPTION_STATUS_NO_TRANS_UPDATE flag here. The send_eof() function
- is used by both the select_insert and the select_create classes,
- so setting it there would clash.
- */
- if (!(table->file->has_transactions() || table->s->tmp_table))
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
-
DBUG_RETURN(res);
}
@@ -2299,7 +2321,7 @@ int select_insert::prepare2(void)
DBUG_ENTER("select_insert::prepare2");
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
!thd->prelocked_mode)
- table->file->start_bulk_insert((ha_rows) 0);
+ table->file->ha_start_bulk_insert((ha_rows) 0);
DBUG_RETURN(0);
}
@@ -2373,6 +2395,7 @@ bool select_insert::send_data(List<Item> &values)
last_insert_id= thd->insert_id();
}
}
+ table->file->release_auto_increment();
DBUG_RETURN(error);
}
@@ -2391,7 +2414,9 @@ void select_insert::send_error(uint errcode,const char *err)
{
DBUG_ENTER("select_insert::send_error");
- my_message(errcode, err, MYF(0));
+ /* Avoid an extra 'unknown error' message if we already reported an error */
+ if (errcode != ER_UNKNOWN_ERROR && !thd->net.report_error)
+ my_message(errcode, err, MYF(0));
if (!table)
{
@@ -2402,7 +2427,7 @@ void select_insert::send_error(uint errcode,const char *err)
DBUG_VOID_RETURN;
}
if (!thd->prelocked_mode)
- table->file->end_bulk_insert();
+ table->file->ha_end_bulk_insert();
/*
If at least one row has been inserted/modified and will stay in the table
(the table doesn't have transactions) we must write to the binlog (and
@@ -2419,11 +2444,8 @@ void select_insert::send_error(uint errcode,const char *err)
INSERT-SELECT.
When replicating a CREATE-SELECT statement, we shall not write the
- events to the binary log. To prevent the ha_rollback_stmt() below
- from writing to the binary log, we have to pretend that the table
- is transactional, even if it actually is not. Therefore, the
- OPTION_STATUS_NO_TRANS_UPDATE is cleared in
- select_create::prepare() and will remain cleared here.
+ events to the binary log and should thus not set
+ OPTION_STATUS_NO_TRANS_UPDATE.
When replicating INSERT-SELECT, we shall not write the events to
the binary log for transactional table, but shall write all events
@@ -2431,22 +2453,22 @@ void select_insert::send_error(uint errcode,const char *err)
this case, the OPTION_STATUS_NO_TRANS_UPDATE is set if there is a
write to a non-transactional table, otherwise it is cleared.
*/
- if ((info.copied || info.deleted || info.updated) &&
- !table->file->has_transactions())
+ if (info.copied || info.deleted || info.updated)
{
- if (last_insert_id)
- thd->insert_id(last_insert_id); // For binary log
- if (mysql_bin_log.is_open())
+ if (!table->file->has_transactions())
{
- thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
- table->file->has_transactions(), FALSE);
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For binary log
+ if (mysql_bin_log.is_open())
+ {
+ thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
+ table->file->has_transactions(), FALSE);
+ }
+ if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
+ !can_rollback_data())
+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ query_cache_invalidate3(thd, table, 1);
}
- if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
- }
- if (info.copied || info.deleted || info.updated)
- {
- query_cache_invalidate3(thd, table, 1);
}
ha_rollback_stmt(thd);
DBUG_VOID_RETURN;
@@ -2458,25 +2480,28 @@ bool select_insert::send_eof()
int error,error2;
DBUG_ENTER("select_insert::send_eof");
- error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
+ error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- /*
- We must invalidate the table in the query cache before binlog writing
- and ha_autocommit_or_rollback.
-
- If nothing was inserted in the table, there is no need to emit a
- ROLLBACK statement to the binary log, so in that case we clear
- OPTION_STATUS_NO_TRANS_UPDATE.
-
- Observe that select_insert::send_eof() is used by both
- select_insert and select_create and that they set the flag in
- different manners. See Note 1 below for more info.
- */
if (info.copied || info.deleted || info.updated)
+ {
+ /*
+ We must invalidate the table in the query cache before binlog writing
+ and ha_autocommit_or_rollback.
+ */
query_cache_invalidate3(thd, table, 1);
- else
- thd->options&= ~OPTION_STATUS_NO_TRANS_UPDATE;
+ /*
+ Mark that we have done permanent changes if all of the below is true
+ - Table doesn't support transactions
+ - It's a normal (not temporary) table. (Changes to temporary tables
+ are not logged in RBR)
+ - We are using statement based replication
+ */
+ if (!table->file->has_transactions() &&
+ (!table->s->tmp_table ||
+ !thd->current_stmt_binlog_row_based))
+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ }
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
@@ -2588,12 +2613,13 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
while ((item=it++))
{
create_field *cr_field;
- Field *field;
+ Field *field, *def_field;
if (item->type() == Item::FUNC_ITEM)
- field=item->tmp_table_field(&tmp_table);
+ field= item->tmp_table_field(&tmp_table);
else
- field=create_tmp_field(thd, &tmp_table, item, item->type(),
- (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0);
+ field= create_tmp_field(thd, &tmp_table, item, item->type(),
+ (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0,
+ 0);
if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
((Item_field *)item)->field :
@@ -2614,9 +2640,9 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
don't want to delete from it) 2) it would be written before the CREATE
TABLE, which is a wrong order. So we keep binary logging disabled when we
open_table().
- NOTE: By locking table which we just have created (or for which we just have
- have found that it already exists) separately from other tables used by the
- statement we create potential window for deadlock.
+ NOTE: By locking table which we just have created (or for which we just
+ have have found that it already exists) separately from other tables used
+ by the statement we create potential window for deadlock.
TODO: create and open should be done atomic !
*/
{
@@ -2674,31 +2700,30 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
}
-int
-select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+class MY_HOOKS : public TABLEOP_HOOKS
{
- DBUG_ENTER("select_create::prepare");
+public:
+ MY_HOOKS(select_create *x) : ptr(x) { }
+ virtual void do_prelock(TABLE **tables, uint count)
+ {
+ if (ptr->get_thd()->current_stmt_binlog_row_based)
+ ptr->binlog_show_create_table(tables, count);
+ }
- class MY_HOOKS : public TABLEOP_HOOKS {
- public:
- MY_HOOKS(select_create *x) : ptr(x) { }
- virtual void do_prelock(TABLE **tables, uint count)
- {
- if (ptr->get_thd()->current_stmt_binlog_row_based)
- ptr->binlog_show_create_table(tables, count);
- }
+private:
+ select_create *ptr;
+};
- private:
- select_create *ptr;
- };
+int select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+{
MY_HOOKS hooks(this);
+ DBUG_ENTER("select_create::prepare");
unit= u;
- table= create_table_from_items(thd, create_info, create_table,
- extra_fields, keys, &values, &lock,
- &hooks);
- if (!table)
+ if (!(table= create_table_from_items(thd, create_info, create_table,
+ extra_fields, keys, &values, &lock,
+ &hooks)))
DBUG_RETURN(-1); // abort() deletes table
if (table->s->fields < values.elements)
@@ -2707,16 +2732,15 @@ 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 */
for (Field **f= field ; *f ; f++)
- (*f)->query_id= thd->query_id;
+ bitmap_set_bit(table->write_set, (*f)->field_index);
/* Don't set timestamp if used */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
table->next_number_field=table->found_next_number_field;
restore_record(table,s->default_values); // Get empty record
@@ -2724,7 +2748,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (!thd->prelocked_mode)
- table->file->start_bulk_insert((ha_rows) 0);
+ table->file->ha_start_bulk_insert((ha_rows) 0);
thd->no_trans_update= 0;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
@@ -2735,8 +2759,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
-void
-select_create::binlog_show_create_table(TABLE **tables, uint count)
+void select_create::binlog_show_create_table(TABLE **tables, uint count)
{
/*
Note 1: In RBR mode, we generate a CREATE TABLE statement for the
@@ -2754,25 +2777,24 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
since there potentially are sub-selects or accesses to information
schema that will do a close_thread_tables(), destroying the
statement transaction cache.
-
- To ensure that the event kaboodle is not written to the binary log
- on rollback, we clear the OPTION_STATUS_NO_TRANS_UPDATE bit of
- thd->options.
- */
+ */
+#ifdef HAVE_ROW_BASED_REPLICATION
DBUG_ASSERT(thd->current_stmt_binlog_row_based);
+#endif
DBUG_ASSERT(tables && *tables && count > 0);
- thd->options&= ~OPTION_STATUS_NO_TRANS_UPDATE;
char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
- query.length(0); // Have to zero it since constructor doesn't
-
+ int result;
TABLE_LIST table_list;
+
memset(&table_list, 0, sizeof(table_list));
table_list.table = *tables;
+ query.length(0); // Have to zero it since constructor doesn't
- int result= store_create_info(thd, &table_list, &query, create_info);
+ result= store_create_info(thd, &table_list, &query, create_info);
DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */
+
thd->binlog_query(THD::STMT_QUERY_TYPE,
query.ptr(), query.length(),
/* is_trans */ TRUE,
@@ -2809,17 +2831,9 @@ bool select_create::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
VOID(pthread_mutex_lock(&LOCK_open));
mysql_unlock_tables(thd, lock);
- /*
- TODO:
- Check if we can remove the following two rows.
- We should be able to just keep the table in the table cache.
- */
if (!table->s->tmp_table)
{
- ulong version= table->s->version;
- hash_delete(&open_cache,(byte*) table);
- /* Tell threads waiting for refresh that something has happened */
- if (version != refresh_version)
+ if (close_thread_table(thd, &table))
VOID(pthread_cond_broadcast(&COND_refresh));
}
lock=0;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 562224201e7..d45f4369095 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -152,8 +152,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->found_semicolon= 0;
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
- lex->leaf_tables_insert= lex->query_tables= 0;
- lex->query_tables_last= &lex->query_tables;
+ lex->leaf_tables_insert= 0;
lex->variables_used= 0;
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
@@ -175,17 +174,12 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->sphead= NULL;
lex->spcont= NULL;
lex->proc_list.first= 0;
- lex->query_tables_own_last= 0;
lex->escape_used= lex->et_compile_phase= FALSE;
+ lex->reset_query_tables_list(FALSE);
lex->name= 0;
lex->et= NULL;
- if (lex->sroutines.records)
- my_hash_reset(&lex->sroutines);
- lex->sroutines_list.empty();
- lex->sroutines_list_own_last= lex->sroutines_list.next;
- lex->sroutines_list_own_elements= 0;
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
@@ -319,18 +313,7 @@ static char *get_text(LEX *lex)
found_escape=1;
if (lex->ptr == lex->end_of_query)
return 0;
-#ifdef USE_MB
- int l;
- if (use_mb(cs) &&
- (l = my_ismbchar(cs,
- (const char *)lex->ptr,
- (const char *)lex->end_of_query))) {
- lex->ptr += l;
- continue;
- }
- else
-#endif
- yySkip();
+ yySkip();
}
else if (c == sep)
{
@@ -360,9 +343,6 @@ static char *get_text(LEX *lex)
{
uchar *to;
- /* Re-use found_escape for tracking state of escapes */
- found_escape= 0;
-
for (to=start ; str != end ; str++)
{
#ifdef USE_MB
@@ -376,8 +356,7 @@ static char *get_text(LEX *lex)
continue;
}
#endif
- if (!found_escape &&
- !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
+ if (!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
*str == '\\' && str+1 != end)
{
switch(*++str) {
@@ -404,20 +383,14 @@ static char *get_text(LEX *lex)
*to++= '\\'; // remember prefix for wildcard
/* Fall through */
default:
- found_escape= 1;
- str--;
+ *to++= *str;
break;
}
}
- else if (!found_escape && *str == sep)
- {
- found_escape= 1;
- }
+ else if (*str == sep)
+ *to++= *str++; // Two ' or "
else
- {
*to++ = *str;
- found_escape= 0;
- }
}
*to=0;
lex->yytoklen=(uint) (to-start);
@@ -1625,6 +1598,52 @@ void st_select_lex::print_limit(THD *thd, String *str)
/*
+ Initialize (or reset) Query_tables_list object.
+
+ SYNOPSIS
+ reset_query_tables_list()
+ init TRUE - we should perform full initialization of object with
+ allocating needed memory
+ FALSE - object is already initialized so we should only reset
+ its state so it can be used for parsing/processing
+ of new statement
+
+ DESCRIPTION
+ This method initializes Query_tables_list so it can be used as part
+ of LEX object for parsing/processing of statement. One can also use
+ this method to reset state of already initialized Query_tables_list
+ so it can be used for processing of new statement.
+*/
+
+void Query_tables_list::reset_query_tables_list(bool init)
+{
+ query_tables= 0;
+ query_tables_last= &query_tables;
+ query_tables_own_last= 0;
+ if (init)
+ hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
+ else if (sroutines.records)
+ my_hash_reset(&sroutines);
+ sroutines_list.empty();
+ sroutines_list_own_last= sroutines_list.next;
+ sroutines_list_own_elements= 0;
+}
+
+
+/*
+ Destroy Query_tables_list object with freeing all resources used by it.
+
+ SYNOPSIS
+ destroy_query_tables_list()
+*/
+
+void Query_tables_list::destroy_query_tables_list()
+{
+ hash_free(&sroutines);
+}
+
+
+/*
Initialize LEX object.
SYNOPSIS
@@ -1640,12 +1659,9 @@ void st_select_lex::print_limit(THD *thd, String *str)
st_lex::st_lex()
:result(0), yacc_yyss(0), yacc_yyvs(0),
- sql_command(SQLCOM_END), query_tables_own_last(0)
+ sql_command(SQLCOM_END)
{
- hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
- sroutines_list.empty();
- sroutines_list_own_last= sroutines_list.next;
- sroutines_list_own_elements= 0;
+ reset_query_tables_list(TRUE);
}
@@ -2029,6 +2045,11 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
SYNOPSIS
st_lex::cleanup_after_one_table_open()
+
+ NOTE
+ This method is mostly responsible for cleaning up of selects lists and
+ derived tables state. To rollback changes in Query_tables_list one has
+ to call Query_tables_list::reset_query_tables_list(FALSE).
*/
void st_lex::cleanup_after_one_table_open()
@@ -2055,11 +2076,41 @@ void st_lex::cleanup_after_one_table_open()
select_lex.cut_subtree();
}
time_zone_tables_used= 0;
- if (sroutines.records)
- my_hash_reset(&sroutines);
- sroutines_list.empty();
- sroutines_list_own_last= sroutines_list.next;
- sroutines_list_own_elements= 0;
+}
+
+
+/*
+ Save current state of Query_tables_list for this LEX, and prepare it
+ for processing of new statemnt.
+
+ SYNOPSIS
+ reset_n_backup_query_tables_list()
+ backup Pointer to Query_tables_list instance to be used for backup
+*/
+
+void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
+{
+ backup->set_query_tables_list(this);
+ /*
+ We have to perform full initialization here since otherwise we
+ will damage backed up state.
+ */
+ this->reset_query_tables_list(TRUE);
+}
+
+
+/*
+ Restore state of Query_tables_list for this LEX from backup.
+
+ SYNOPSIS
+ restore_backup_query_tables_list()
+ backup Pointer to Query_tables_list instance used for backup
+*/
+
+void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
+{
+ this->destroy_query_tables_list();
+ this->set_query_tables_list(backup);
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f0bd85367d0..77f79ad61f4 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -110,8 +110,10 @@ enum enum_sql_command {
SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
SQLCOM_SHOW_PLUGINS,
+ SQLCOM_SHOW_CONTRIBUTORS,
SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
- SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
+ SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
+ SQLCOM_SHOW_SCHEDULER_STATUS,
/* This should be the last !!! */
@@ -750,9 +752,95 @@ extern sys_var *trg_new_row_fake_var;
enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
XA_SUSPEND, XA_FOR_MIGRATE};
+
+/*
+ Class representing list of all tables used by statement.
+ It also contains information about stored functions used by statement
+ since during its execution we may have to add all tables used by its
+ stored functions/triggers to this list in order to pre-open and lock
+ them.
+
+ Also used by st_lex::reset_n_backup/restore_backup_query_tables_list()
+ methods to save and restore this information.
+*/
+
+class Query_tables_list
+{
+public:
+ /* Global list of all tables used by this statement */
+ TABLE_LIST *query_tables;
+ /* Pointer to next_global member of last element in the previous list. */
+ TABLE_LIST **query_tables_last;
+ /*
+ If non-0 then indicates that query requires prelocking and points to
+ next_global member of last own element in query table list (i.e. last
+ table which was not added to it as part of preparation to prelocking).
+ 0 - indicates that this query does not need prelocking.
+ */
+ TABLE_LIST **query_tables_own_last;
+ /* Set of stored routines called by statement. */
+ HASH sroutines;
+ /*
+ List linking elements of 'sroutines' set. Allows you to add new elements
+ to this set as you iterate through the list of existing elements.
+ 'sroutines_list_own_last' is pointer to ::next member of last element of
+ this list which represents routine which is explicitly used by query.
+ 'sroutines_list_own_elements' number of explicitly used routines.
+ We use these two members for restoring of 'sroutines_list' to the state
+ in which it was right after query parsing.
+ */
+ SQL_LIST sroutines_list;
+ byte **sroutines_list_own_last;
+ uint sroutines_list_own_elements;
+
+ /*
+ These constructor and destructor serve for creation/destruction
+ of Query_tables_list instances which are used as backup storage.
+ */
+ Query_tables_list() {}
+ ~Query_tables_list() {}
+
+ /* Initializes (or resets) Query_tables_list object for "real" use. */
+ void reset_query_tables_list(bool init);
+ void destroy_query_tables_list();
+ void set_query_tables_list(Query_tables_list *state)
+ {
+ *this= *state;
+ }
+
+ void add_to_query_tables(TABLE_LIST *table)
+ {
+ *(table->prev_global= query_tables_last)= table;
+ query_tables_last= &table->next_global;
+ }
+ bool requires_prelocking()
+ {
+ return test(query_tables_own_last);
+ }
+ void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
+ {
+ query_tables_own_last= tables_own_last;
+ }
+ /* Return pointer to first not-own table in query-tables or 0 */
+ TABLE_LIST* first_not_own_table()
+ {
+ return ( query_tables_own_last ? *query_tables_own_last : 0);
+ }
+ void chop_off_not_own_tables()
+ {
+ if (query_tables_own_last)
+ {
+ *query_tables_own_last= 0;
+ query_tables_last= query_tables_own_last;
+ query_tables_own_last= 0;
+ }
+ }
+};
+
+
/* The state of the lex parsing. This is saved in the THD struct */
-typedef struct st_lex
+typedef struct st_lex : public Query_tables_list
{
uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval;
@@ -785,14 +873,6 @@ typedef struct st_lex
gptr yacc_yyss,yacc_yyvs;
THD *thd;
CHARSET_INFO *charset;
- TABLE_LIST *query_tables; /* global list of all tables in this query */
- /*
- last element next_global of previous list (used only for list building
- during parsing and VIEW processing. This pointer could be invalid during
- processing of information schema tables(see get_schema_tables_result
- function)
- */
- TABLE_LIST **query_tables_last;
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
/* Position (first character index) of SELECT of CREATE VIEW statement */
@@ -933,20 +1013,6 @@ typedef struct st_lex
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
bool all_privileges;
sp_pcontext *spcont;
- /* Set of stored routines called by statement. */
- HASH sroutines;
- /*
- List linking elements of 'sroutines' set. Allows you to add new elements
- to this set as you iterate through the list of existing elements.
- 'sroutines_list_own_last' is pointer to ::next member of last element of
- this list which represents routine which is explicitly used by query.
- 'sroutines_list_own_elements' number of explicitly used routines.
- We use these two members for restoring of 'sroutines_list' to the state
- in which it was right after query parsing.
- */
- SQL_LIST sroutines_list;
- byte **sroutines_list_own_last;
- uint sroutines_list_own_elements;
st_sp_chistics sp_chistics;
@@ -987,14 +1053,6 @@ typedef struct st_lex
const char *stmt_definition_begin;
/*
- If non-0 then indicates that query requires prelocking and points to
- next_global member of last own element in query table list (i.e. last
- table which was not added to it as part of preparation to prelocking).
- 0 - indicates that this query does not need prelocking.
- */
- TABLE_LIST **query_tables_own_last;
-
- /*
Pointers to part of LOAD DATA statement that should be rewritten
during replication ("LOCAL 'filename' REPLACE INTO" part).
*/
@@ -1012,7 +1070,7 @@ typedef struct st_lex
virtual ~st_lex()
{
- hash_free(&sroutines);
+ destroy_query_tables_list();
}
inline void uncacheable(uint8 cause)
@@ -1037,11 +1095,6 @@ typedef struct st_lex
TABLE_LIST *unlink_first_table(bool *link_to_local);
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
void first_lists_tables_same();
- inline void add_to_query_tables(TABLE_LIST *table)
- {
- *(table->prev_global= query_tables_last)= table;
- query_tables_last= &table->next_global;
- }
bool add_time_zone_tables_to_query_tables(THD *thd);
bool can_be_merged();
@@ -1073,28 +1126,7 @@ typedef struct st_lex
return FALSE;
}
}
- inline bool requires_prelocking()
- {
- return test(query_tables_own_last);
- }
- inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
- {
- query_tables_own_last= tables_own_last;
- }
- /* Return pointer to first not-own table in query-tables or 0 */
- TABLE_LIST* first_not_own_table()
- {
- return ( query_tables_own_last ? *query_tables_own_last : 0);
- }
- void chop_off_not_own_tables()
- {
- if (query_tables_own_last)
- {
- *query_tables_own_last= 0;
- query_tables_last= query_tables_own_last;
- query_tables_own_last= 0;
- }
- }
+
void cleanup_after_one_table_open();
bool push_context(Name_resolution_context *context)
@@ -1111,6 +1143,9 @@ typedef struct st_lex
{
return context_stack.head();
}
+
+ void reset_n_backup_query_tables_list(Query_tables_list *backup);
+ void restore_backup_query_tables_list(Query_tables_list *backup);
} LEX;
struct st_lex_local: public st_lex
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index bf8a6b8cfbe..f8debbedc62 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -117,11 +117,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
char name[FN_REFLEN];
File file;
- TABLE *table;
+ TABLE *table= NULL;
int error;
String *field_term=ex->field_term,*escaped=ex->escaped;
String *enclosed=ex->enclosed;
- Item *unused_conds= 0;
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
@@ -153,10 +152,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ha_enable_transaction(thd, FALSE);
if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(TRUE);
- if (setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- table_list, &unused_conds,
- &thd->lex->select_lex.leaf_tables, FALSE))
+ if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
+ table_list,
+ &thd->lex->select_lex.leaf_tables, FALSE,
+ INSERT_ACL | UPDATE_ACL))
DBUG_RETURN(-1);
if (!table_list->table || // do not suport join view
!table_list->updatable || // and derived tables
@@ -187,51 +187,48 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table= table_list->table;
transactional_table= table->file->has_transactions();
+ if (table->found_next_number_field)
+ table->mark_auto_increment_column();
+
if (!fields_vars.elements)
{
Field **field;
for (field=table->field; *field ; field++)
fields_vars.push_back(new Item_field(*field));
- /*
- Since all fields are set we set all bits in the write set
- */
- table->file->ha_set_all_bits_in_write_set();
+ bitmap_set_all(table->write_set);
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/*
Let us also prepare SET clause, altough it is probably empty
in this case.
*/
- if (setup_fields(thd, 0, set_fields, 1, 0, 0) ||
- setup_fields(thd, 0, set_values, 1, 0, 0))
+ if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+ setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(TRUE);
}
else
{ // Part field list
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
- /*
- Indicate that both variables in field list and fields in update_list
- is to be included in write set of table. We do however set all bits
- in write set anyways since it is not allowed to specify NULLs in
- LOAD DATA
- */
- table->file->ha_set_all_bits_in_write_set();
- if (setup_fields(thd, 0, fields_vars, 2, 0, 0) ||
- setup_fields(thd, 0, set_fields, 2, 0, 0) ||
+ if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
+ setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/*
Check whenever TIMESTAMP field with auto-set feature specified
explicitly.
*/
- if (table->timestamp_field &&
- table->timestamp_field->query_id == thd->query_id)
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- /*
- Fix the expressions in SET clause. This should be done after
- check_that_all_fields_are_given_values() and setting use_timestamp
- since it may update query_id for some fields.
- */
- if (setup_fields(thd, 0, set_values, 1, 0, 0))
+ if (table->timestamp_field)
+ {
+ if (bitmap_is_set(table->write_set,
+ table->timestamp_field->field_index))
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ else
+ {
+ bitmap_set_bit(table->write_set,
+ table->timestamp_field->field_index);
+ }
+ }
+ /* Fix the expressions in SET clause */
+ if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(TRUE);
}
@@ -366,7 +363,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
handle_duplicates == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (!thd->prelocked_mode)
- table->file->start_bulk_insert((ha_rows) 0);
+ table->file->ha_start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
thd->no_trans_update= 0;
@@ -383,7 +380,7 @@ bool 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->end_bulk_insert() && !error)
+ if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
{
table->file->print_error(my_errno, MYF(0));
error= 1;
@@ -505,6 +502,8 @@ err:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (table != NULL)
+ table->file->release_auto_increment();
thd->abort_on_warning= 0;
DBUG_RETURN(error);
}
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index b457ff5a6d6..3d06030536f 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -155,9 +155,11 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (setup_tables(lex->thd, &select_lex->context, &select_lex->top_join_list,
(TABLE_LIST *)select_lex->table_list.first
- &select_lex->where, &select_lex->leaf_tables, FALSE) ||
- setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) ||
- setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1))
+ &select_lex->leaf_tables, FALSE) ||
+ setup_fields(lex->thd, 0, select_lex->item_list, MARK_COLUMNS_READ,
+ &all_fields,1) ||
+ setup_fields(lex->thd, 0, item_list_copy, MARK_COLUMNS_READ,
+ &all_fields, 1))
return -1;
if (select_lex->olap == CUBE_TYPE)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 33b3118de1a..14847a9906d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -162,8 +162,9 @@ bool end_active_trans(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
}
+ thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
DBUG_RETURN(error);
}
@@ -186,8 +187,7 @@ bool begin_trans(THD *thd)
else
{
LEX *lex= thd->lex;
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- OPTION_BEGIN);
+ thd->options|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
error= ha_start_consistent_snapshot(thd);
@@ -398,7 +398,7 @@ int check_user(THD *thd, enum enum_server_command command,
NO_ACCESS)) // authentication is OK
{
DBUG_PRINT("info",
- ("Capabilities: %d packet_length: %ld Host: '%s' "
+ ("Capabilities: %lx packet_length: %ld Host: '%s' "
"Login user: '%s' Priv_user: '%s' Using password: %s "
"Access: %u db: '%s'",
thd->client_capabilities,
@@ -1439,7 +1439,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
*/
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
res= ha_commit(thd);
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
break;
case COMMIT_RELEASE:
do_release= 1; /* fall through */
@@ -1456,7 +1457,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_rollback(thd))
res= -1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
if (!res && (completion == ROLLBACK_AND_CHAIN))
res= begin_trans(thd);
break;
@@ -2008,13 +2010,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#else
char *buff= thd->net.last_error;
#endif
+
+ STATUS_VAR current_global_status_var;
+ calc_sum_of_all_status(&current_global_status_var);
+
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
"Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f",
uptime,
(int) thread_count, (ulong) thd->query_id,
- (ulong) thd->status_var.long_query_count,
- thd->status_var.opened_tables, refresh_version,
+ current_global_status_var.long_query_count,
+ current_global_status_var.opened_tables, refresh_version,
cached_open_tables(),
(uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
(double) 0));
@@ -2049,7 +2055,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id,false);
+ sql_kill(thd,id,false);
break;
}
case COM_SET_OPTION:
@@ -2737,8 +2743,7 @@ mysql_execute_command(THD *thd)
goto error;
if (end_active_trans(thd))
goto error;
- else
- res = load_master_data(thd);
+ res = load_master_data(thd);
break;
#endif /* HAVE_REPLICATION */
case SQLCOM_SHOW_ENGINE_STATUS:
@@ -2802,11 +2807,6 @@ mysql_execute_command(THD *thd)
break;
}
}
- else
- {
- /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
- }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
// Skip first table, which is the table we are creating
@@ -2931,6 +2931,9 @@ mysql_execute_command(THD *thd)
}
else
{
+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
+ if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ thd->options|= OPTION_KEEP_LOG;
/* regular create */
if (lex->like_name)
res= mysql_create_like_table(thd, create_table, &lex->create_info,
@@ -3501,7 +3504,7 @@ end_with_restore_list:
lex->drop_if_exists= 1;
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->options|= OPTION_KEEP_LOG;
}
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
@@ -3531,6 +3534,9 @@ end_with_restore_list:
case SQLCOM_SHOW_AUTHORS:
res= mysqld_show_authors(thd);
break;
+ case SQLCOM_SHOW_CONTRIBUTORS:
+ res= mysqld_show_contributors(thd);
+ break;
case SQLCOM_SHOW_PRIVILEGES:
res= mysqld_show_privileges(thd);
break;
@@ -3836,14 +3842,17 @@ end_with_restore_list:
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
- res= evex_create_event(thd, lex->et, (uint) lex->create_info.options,
- &rows_affected);
+ res= Events::create_event(thd, lex->et,
+ (uint) lex->create_info.options,
+ &rows_affected);
break;
case SQLCOM_ALTER_EVENT:
- res= evex_update_event(thd, lex->et, lex->spname, &rows_affected);
+ res= Events::update_event(thd, lex->et, lex->spname,
+ &rows_affected);
break;
case SQLCOM_DROP_EVENT:
- res= evex_drop_event(thd, lex->et, lex->drop_if_exists, &rows_affected);
+ res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
+ &rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
@@ -3881,9 +3890,16 @@ end_with_restore_list:
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
goto error;
}
- res= evex_show_create_event(thd, lex->spname, lex->et->definer);
+ res= Events::show_create_event(thd, lex->spname);
+ break;
+ }
+#ifndef DBUG_OFF
+ case SQLCOM_SHOW_SCHEDULER_STATUS:
+ {
+ res= Events::dump_internal_status(thd);
break;
}
+#endif
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
@@ -4123,7 +4139,7 @@ end_with_restore_list:
MYF(0));
goto error;
}
- kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
+ sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4225,7 +4241,8 @@ end_with_restore_list:
res= TRUE; // cannot happen
else
{
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ if ((thd->options &
+ (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)) &&
!thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
@@ -4956,7 +4973,8 @@ end_with_restore_list:
thd->transaction.xid_state.xa_state=XA_ACTIVE;
thd->transaction.xid_state.xid.set(thd->lex->xid);
xid_cache_insert(&thd->transaction.xid_state);
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
+ thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
@@ -5050,7 +5068,8 @@ end_with_restore_list:
xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5080,7 +5099,8 @@ end_with_restore_list:
my_error(ER_XAER_RMERR, MYF(0));
else
send_ok(thd);
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
+ OPTION_KEEP_LOG);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5175,23 +5195,35 @@ error:
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
+ Security_context * backup_ctx= thd->security_ctx;
+
+ /* we need to switch to the saved context (if any) */
+ if (all_tables->security_ctx)
+ thd->security_ctx= all_tables->security_ctx;
+
if (check_access(thd, privilege, all_tables->db,
&all_tables->grant.privilege, 0, 0,
test(all_tables->schema_table)))
- return 1;
+ goto deny;
/* Show only 1 table for check_grant */
if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
- return 1;
+ goto deny;
+
+ thd->security_ctx= backup_ctx;
/* Check rights on tables of subselects and implictly opened tables */
TABLE_LIST *subselects_tables;
if ((subselects_tables= all_tables->next_global))
{
if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
- return 1;
+ goto deny;
}
return 0;
+
+deny:
+ thd->security_ctx= backup_ctx;
+ return 1;
}
@@ -5372,6 +5404,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
ulong found_access=0;
TABLE_LIST *org_tables= tables;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
+ Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
/*
The check that first_not_own_table is not reached is for the case when
the given table list refers to the list for prelocking (contains tables
@@ -5379,12 +5412,17 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
*/
for (; tables != first_not_own_table; tables= tables->next_global)
{
+ if (tables->security_ctx)
+ sctx= tables->security_ctx;
+ else
+ sctx= backup_ctx;
+
if (tables->schema_table &&
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
{
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->security_ctx->priv_user, thd->security_ctx->priv_host,
+ sctx->priv_user, sctx->priv_host,
information_schema_name.str);
return TRUE;
}
@@ -5393,12 +5431,13 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
Remove SHOW_VIEW_ACL, because it will be checked during making view
*/
tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
- if (tables->derived || tables->schema_table || tables->belong_to_view ||
+ if (tables->derived || tables->schema_table ||
(tables->table && (int)tables->table->s->tmp_table) ||
my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used))
continue;
- if ((thd->security_ctx->master_access & want_access) ==
+ thd->security_ctx= sctx;
+ if ((sctx->master_access & want_access) ==
(want_access & ~EXTRA_ACL) &&
thd->db)
tables->grant.privilege= want_access;
@@ -5410,19 +5449,23 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
- return TRUE; // Access denied
+ goto deny; // Access denied
found_access=tables->grant.privilege;
found=1;
}
}
else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
- return TRUE;
+ goto deny;
}
+ thd->security_ctx= backup_ctx;
if (grant_option)
return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
return FALSE;
+deny:
+ thd->security_ctx= backup_ctx;
+ return TRUE;
}
@@ -5673,6 +5716,14 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
+ /*
+ If in autocommit mode and not in a transaction, reset
+ OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
+ in ha_rollback_trans() about some tables couldn't be rolled back.
+ */
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ thd->options&= ~(OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG);
+
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->tmp_table_used= 0;
if (!thd->in_sub_stmt)
@@ -6917,22 +6968,26 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
return result;
}
+
/*
- kill on thread
+ kills a thread
SYNOPSIS
kill_one_thread()
thd Thread class
id Thread id
+ only_kill_query Should it kill the query or the connection
NOTES
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
+ DBUG_ENTER("kill_one_thread");
+ DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@@ -6958,8 +7013,25 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
error=ER_KILL_DENIED_ERROR;
pthread_mutex_unlock(&tmp->LOCK_delete);
}
+ DBUG_PRINT("exit", ("%d", error));
+ DBUG_RETURN(error);
+}
+
+
+/*
+ kills a thread and sends response
+
+ SYNOPSIS
+ sql_kill()
+ thd Thread class
+ id Thread id
+ only_kill_query Should it kill the query or the connection
+*/
- if (!error)
+void sql_kill(THD *thd, ulong id, bool only_kill_query)
+{
+ uint error;
+ if (!(error= kill_one_thread(thd, id, only_kill_query)))
send_ok(thd);
else
my_error(error, MYF(0), id);
@@ -7109,7 +7181,7 @@ bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= (handlerton*) &default_hton;
+ create_info.db_type= 0;
create_info.default_table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
&create_info, table_list,
@@ -7125,7 +7197,7 @@ bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= (handlerton*) &default_hton;
+ create_info.db_type= 0;
create_info.default_table_charset= thd->variables.collation_database;
alter_info->clear();
alter_info->flags= ALTER_DROP_INDEX;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index e946e972968..a10a04ba9f9 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -849,7 +849,7 @@ static bool fix_fields_part_func(THD *thd, TABLE_LIST *tables,
context->table_list= tables;
context->first_name_resolution_table= tables;
context->last_name_resolution_table= NULL;
- func_expr->walk(&Item::change_context_processor, (byte*) context);
+ func_expr->walk(&Item::change_context_processor, 0, (byte*) context);
save_where= thd->where;
thd->where= "partition function";
error= func_expr->fix_fields(thd, (Item**)0);
@@ -1335,7 +1335,7 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
char db_name_string[FN_REFLEN];
char* db_name;
partition_info *part_info= table->part_info;
- ulong save_set_query_id= thd->set_query_id;
+ enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
Item *thd_free_list= thd->free_list;
DBUG_ENTER("fix_partition_func");
@@ -1343,8 +1343,8 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
{
DBUG_RETURN(FALSE);
}
- thd->set_query_id= 0;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= MARK_COLUMNS_NONE;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
/*
Set-up the TABLE_LIST object to be a list with a single table
Set the object to zero to create NULL pointers and set alias
@@ -1484,8 +1484,8 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
result= FALSE;
end:
thd->free_list= thd_free_list;
- thd->set_query_id= save_set_query_id;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= save_mark_used_columns;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(result);
}
@@ -1665,8 +1665,8 @@ static int add_keyword_int(File fptr, const char *keyword, longlong num)
static int add_engine(File fptr, handlerton *engine_type)
{
- const char *engine_str= engine_type->name;
- DBUG_PRINT("info", ("ENGINE = %s", engine_str));
+ const char *engine_str= hton2plugin[engine_type->slot]->name.str;
+ DBUG_PRINT("info", ("ENGINE: %s", engine_str));
int err= add_string(fptr, "ENGINE = ");
return err + add_string(fptr, engine_str);
}
@@ -1676,7 +1676,7 @@ static int add_partition_options(File fptr, partition_element *p_elem)
int err= 0;
if (p_elem->tablespace_name)
- err+= add_keyword_string(fptr,"TABLESPACE", FALSE,
+ err+= add_keyword_string(fptr,"TABLESPACE", FALSE,
p_elem->tablespace_name);
if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
err+= add_keyword_int(fptr,"NODEGROUP",(longlong)p_elem->nodegroup_id);
@@ -1754,7 +1754,6 @@ end:
buf_length A pointer to the returned buffer length
use_sql_alloc Allocate buffer from sql_alloc if true
otherwise use my_malloc
- write_all Write everything, also default values
RETURN VALUES
NULL error
@@ -1782,8 +1781,7 @@ end:
char *generate_partition_syntax(partition_info *part_info,
uint *buf_length,
- bool use_sql_alloc,
- bool write_all)
+ bool use_sql_alloc)
{
uint i,j, tot_no_parts, no_subparts, no_parts;
partition_element *part_elem;
@@ -1843,6 +1841,8 @@ char *generate_partition_syntax(partition_info *part_info,
{
err+= add_subpartition_by(fptr);
/* Must be hash partitioning for subpartitioning */
+ if (part_info->linear_hash_ind)
+ err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
if (part_info->list_of_subpart_fields)
err+= add_key_partition(fptr, part_info->subpart_field_list);
else
@@ -1863,7 +1863,7 @@ char *generate_partition_syntax(partition_info *part_info,
tot_no_parts= part_info->partitions.elements;
no_subparts= part_info->no_subparts;
- if (write_all || (!part_info->use_default_partitions))
+ if (!part_info->use_default_partitions)
{
bool first= TRUE;
err+= add_begin_parenthesis(fptr);
@@ -1884,10 +1884,12 @@ char *generate_partition_syntax(partition_info *part_info,
err+= add_name_string(fptr, part_elem->partition_name);
err+= add_space(fptr);
err+= add_partition_values(fptr, part_info, part_elem);
- if (!part_info->is_sub_partitioned())
+ if (!part_info->is_sub_partitioned() ||
+ part_info->use_default_subpartitions)
+ {
err+= add_partition_options(fptr, part_elem);
- if (part_info->is_sub_partitioned() &&
- (write_all || (!part_info->use_default_subpartitions)))
+ }
+ else
{
err+= add_space(fptr);
err+= add_begin_parenthesis(fptr);
@@ -1990,10 +1992,7 @@ bool partition_key_modified(TABLE *table, List<Item> &fields)
in function
*/
-static
-inline
-longlong
-part_val_int(Item *item_expr)
+static inline longlong part_val_int(Item *item_expr)
{
longlong value= item_expr->val_int();
if (item_expr->null_value)
@@ -2197,9 +2196,11 @@ static uint32 get_part_id_linear_key(partition_info *part_info,
out:part_id The partition id is returned through this pointer
RETURN VALUE
- part_id
- return TRUE means that the fields of the partition function didn't fit
- into any partition and thus the values of the PF-fields are not allowed.
+ part_id Partition id of partition that would contain
+ row with given values of PF-fields
+ HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
+ fit into any partition and thus the values of
+ the PF-fields are not allowed.
DESCRIPTION
A routine used from write_row, update_row and delete_row from any
@@ -2238,9 +2239,11 @@ static uint32 get_part_id_linear_key(partition_info *part_info,
out:part_id The partition id is returned through this pointer
RETURN VALUE
- part_id
- return TRUE means that the fields of the partition function didn't fit
- into any partition and thus the values of the PF-fields are not allowed.
+ part_id Partition id of partition that would contain
+ row with given values of PF-fields
+ HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
+ fit into any partition and thus the values of
+ the PF-fields are not allowed.
DESCRIPTION
@@ -2406,10 +2409,12 @@ int get_partition_id_range(partition_info *part_info,
loc_part_id++;
*part_id= (uint32)loc_part_id;
*func_value= part_func_value;
- if (loc_part_id == max_partition)
- if (range_array[loc_part_id] != LONGLONG_MAX)
- if (part_func_value >= range_array[loc_part_id])
- DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+ if (loc_part_id == max_partition &&
+ range_array[loc_part_id] != LONGLONG_MAX &&
+ part_func_value >= range_array[loc_part_id])
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
+ DBUG_PRINT("exit",("partition: %d", *part_id));
DBUG_RETURN(0);
}
@@ -3559,17 +3564,9 @@ static bool check_engine_condition(partition_element *p_elem,
DBUG_ENTER("check_engine_condition");
DBUG_PRINT("enter", ("def_eng = %u, first = %u", default_engine, *first));
- if (*engine_type)
- DBUG_PRINT("info", ("engine_type = %s", (*engine_type)->name));
- else
- DBUG_PRINT("info", ("engine_type = NULL"));
if (*first && default_engine)
{
*engine_type= p_elem->engine_type;
- if (*engine_type)
- DBUG_PRINT("info", ("engine_type changed to = %s", (*engine_type)->name));
- else
- DBUG_PRINT("info", ("engine_type changed to = NULL"));
}
*first= FALSE;
if ((!default_engine &&
@@ -3879,6 +3876,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
DBUG_RETURN(TRUE);
}
alt_part_info->part_type= tab_part_info->part_type;
+ alt_part_info->subpart_type= tab_part_info->subpart_type;
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
ULL(0),
tab_part_info->no_parts))
@@ -4321,6 +4319,15 @@ state of p1.
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
+ alt_part_info->part_type= tab_part_info->part_type;
+ alt_part_info->subpart_type= tab_part_info->subpart_type;
+ DBUG_ASSERT(!alt_part_info->use_default_partitions);
+ if (alt_part_info->set_up_defaults_for_partitioning(table->file,
+ ULL(0),
+ 0))
+ {
+ DBUG_RETURN(TRUE);
+ }
/*
Online handling:
REORGANIZE PARTITION:
@@ -4457,7 +4464,7 @@ the generated partition syntax in a correct manner.
tab_part_info->use_default_no_subpartitions= FALSE;
}
if (tab_part_info->check_partition_info((handlerton**)NULL,
- table->file, ULL(0)))
+ table->file, ULL(0)))
{
DBUG_RETURN(TRUE);
}
@@ -4523,8 +4530,8 @@ the generated partition syntax in a correct manner.
DBUG_PRINT("info", ("No explicit engine used"));
create_info->db_type= table->part_info->default_engine_type;
}
- DBUG_PRINT("info", ("New engine type = %s",
- create_info->db_type->name));
+ DBUG_PRINT("info", ("New engine type: %s",
+ hton2plugin[create_info->db_type->slot]->name.str));
thd->work_part_info= NULL;
*partition_changed= TRUE;
}
@@ -4586,11 +4593,9 @@ the generated partition syntax in a correct manner.
}
if (!is_native_partitioned)
{
- DBUG_ASSERT(create_info->db_type != &default_hton);
+ DBUG_ASSERT(create_info->db_type);
create_info->db_type= &partition_hton;
}
- DBUG_PRINT("info", ("default_engine_type = %s",
- thd->work_part_info->default_engine_type->name));
}
}
DBUG_RETURN(FALSE);
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index fd2c474236f..87f9a751ca3 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -69,8 +69,7 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
bool fix_partition_func(THD *thd, const char *name, TABLE *table,
bool create_table_ind);
char *generate_partition_syntax(partition_info *part_info,
- uint *buf_length, bool use_sql_alloc,
- bool write_all);
+ uint *buf_length, bool use_sql_alloc);
bool partition_key_modified(TABLE *table, List<Item> &fields);
void get_partition_set(const TABLE *table, byte *buf, const uint index,
const key_range *key_spec,
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 01faae22c57..c15b484f448 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -23,12 +23,18 @@ extern struct st_mysql_plugin *mysqld_builtins[];
char *opt_plugin_dir_ptr;
char opt_plugin_dir[FN_REFLEN];
-LEX_STRING plugin_type_names[]=
+LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
{ (char *)STRING_WITH_LEN("UDF") },
{ (char *)STRING_WITH_LEN("STORAGE ENGINE") },
{ (char *)STRING_WITH_LEN("FTPARSER") }
};
+
+plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
+{
+ 0,ha_initialize_handlerton,0
+};
+
static const char *plugin_interface_version_sym=
"_mysql_plugin_interface_version_";
static const char *sizeof_st_plugin_sym=
@@ -41,8 +47,8 @@ static int min_plugin_interface_version= 0x0000;
static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0x0000,
- 0x0000,
- 0x0000
+ MYSQL_HANDLERTON_INTERFACE_VERSION,
+ MYSQL_FTPARSER_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
@@ -50,6 +56,7 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION
};
+
static DYNAMIC_ARRAY plugin_dl_array;
static DYNAMIC_ARRAY plugin_array;
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
@@ -522,27 +529,15 @@ static int plugin_initialize(struct st_plugin_int *plugin)
{
sql_print_error("Plugin '%s' init function returned error.",
plugin->name.str);
- DBUG_PRINT("warning", ("Plugin '%s' init function returned error.",
- plugin->name.str));
goto err;
}
}
-
- switch (plugin->plugin->type)
+ if (plugin_type_initialize[plugin->plugin->type] &&
+ (*plugin_type_initialize[plugin->plugin->type])(plugin))
{
- case MYSQL_STORAGE_ENGINE_PLUGIN:
- if (ha_initialize_handlerton(plugin))
- {
- sql_print_error("Plugin '%s' handlerton init returned error.",
- plugin->name.str);
- DBUG_PRINT("warning", ("Plugin '%s' handlerton init returned error.",
- plugin->name.str));
- goto err;
- }
- break;
-
- default:
- break;
+ sql_print_error("Plugin '%s' registration as a %s failed.",
+ plugin->name.str, plugin_type_names[plugin->plugin->type]);
+ goto err;
}
DBUG_RETURN(0);
@@ -554,14 +549,14 @@ static int plugin_finalize(THD *thd, struct st_plugin_int *plugin)
{
int rc;
DBUG_ENTER("plugin_finalize");
-
+
if (plugin->ref_count)
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"Plugin is busy and will be uninstalled on shutdown");
goto err;
}
-
+
switch (plugin->plugin->type)
{
case MYSQL_STORAGE_ENGINE_PLUGIN:
@@ -591,7 +586,7 @@ static int plugin_finalize(THD *thd, struct st_plugin_int *plugin)
goto err;
}
}
-
+
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -676,7 +671,7 @@ int plugin_init(void)
get_hash_key, NULL, 0))
goto err;
}
-
+
/* Register all the built-in plugins */
for (builtins= mysqld_builtins; *builtins; builtins++)
{
@@ -684,6 +679,12 @@ int plugin_init(void)
{
if (plugin_register_builtin(plugin))
goto err;
+ struct st_plugin_int *tmp=dynamic_element(&plugin_array,
+ plugin_array.elements-1,
+ struct st_plugin_int *);
+ if (plugin_initialize(tmp))
+ goto err;
+ tmp->state= PLUGIN_IS_READY;
}
}
@@ -758,6 +759,7 @@ void plugin_load(void)
}
table= tables.table;
init_read_record(&read_record_info, new_thd, table, NULL, 1, 0);
+ table->use_all_columns();
while (!(error= read_record_info.read_record(&read_record_info)))
{
DBUG_PRINT("info", ("init plugin record"));
@@ -841,6 +843,7 @@ my_bool mysql_install_plugin(THD *thd, LEX_STRING *name, LEX_STRING *dl)
tmp->state= PLUGIN_IS_READY;
+ table->use_all_columns();
restore_record(table, s->default_values);
table->field[0]->store(name->str, name->length, system_charset_info);
table->field[1]->store(dl->str, dl->length, files_charset_info);
@@ -897,8 +900,8 @@ my_bool mysql_uninstall_plugin(THD *thd, LEX_STRING *name)
else
plugin->state= PLUGIN_IS_DELETED;
+ table->use_all_columns();
table->field[0]->store(name->str, name->length, system_charset_info);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (! table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 672db105cd1..b013beaba1f 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -58,9 +58,12 @@ struct st_plugin_int
struct st_mysql_plugin *plugin;
struct st_plugin_dl *plugin_dl;
enum enum_plugin_state state;
- uint ref_count; /* number of threads using the plugin */
+ uint ref_count; /* number of threads using the plugin */
+ void *data; /* plugin type specific, e.g. handlerton */
};
+typedef int (*plugin_type_init)(struct st_plugin_int *);
+
extern char *opt_plugin_dir_ptr;
extern char opt_plugin_dir[FN_REFLEN];
extern LEX_STRING plugin_type_names[];
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 14bcb437337..078c7e01d5a 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -621,6 +621,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
param->value.cs_info.character_set_client=
thd->variables.character_set_client;
+ DBUG_ASSERT(thd->variables.character_set_client);
param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
@@ -1066,7 +1067,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
its.rewind();
if (table_list->lock_type == TL_WRITE_DELAYED &&
- !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
+ !(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ?
table_list->view_name.str :
@@ -1081,7 +1082,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, 0, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
goto error;
}
}
@@ -1168,7 +1169,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
+ res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@@ -1179,7 +1180,7 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
- if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
+ if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
goto error;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0);
@@ -1333,7 +1334,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (open_and_lock_tables(thd, tables))
DBUG_RETURN(TRUE);
- DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0));
+ DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 918c9f507e2..baea34f2d0b 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1295,12 +1295,12 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
bool mysql_show_binlog_events(THD* thd)
{
Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysql_show_binlog_events");
List<Item> field_list;
const char *errmsg = 0;
bool ret = TRUE;
IO_CACHE log;
File file = -1;
+ DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
if (protocol->send_fields(&field_list,
@@ -1354,12 +1354,12 @@ bool mysql_show_binlog_events(THD* thd)
pthread_mutex_lock(log_lock);
/*
- open_binlog() sought to position 4.
- Read the first event in case it's a Format_description_log_event, to
- know the format. If there's no such event, we are 3.23 or 4.x. This
- code, like before, can't read 3.23 binlogs.
- This code will fail on a mixed relay log (one which has Format_desc then
- Rotate then Format_desc).
+ open_binlog() sought to position 4.
+ Read the first event in case it's a Format_description_log_event, to
+ know the format. If there's no such event, we are 3.23 or 4.x. This
+ code, like before, can't read 3.23 binlogs.
+ This code will fail on a mixed relay log (one which has Format_desc then
+ Rotate then Format_desc).
*/
ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event);
@@ -1383,7 +1383,8 @@ bool mysql_show_binlog_events(THD* thd)
}
for (event_count = 0;
- (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event)); )
+ (ev = Log_event::read_log_event(&log,(pthread_mutex_t*) 0,
+ description_event)); )
{
if (event_count >= limit_start &&
ev->net_send(protocol, linfo.log_file_name, pos))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 810b7789f3d..2cd14c3f5e6 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -337,12 +337,13 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
if ((!(select_options & OPTION_SETUP_TABLES_DONE) &&
- setup_tables(thd, &select_lex->context, join_list,
- tables_list, &conds, &select_lex->leaf_tables,
- FALSE)) ||
+ setup_tables_and_check_access(thd, &select_lex->context, join_list,
+ tables_list,
+ &select_lex->leaf_tables, FALSE,
+ SELECT_ACL)) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
- setup_fields(thd, (*rref_pointer_array), fields_list, 1,
+ setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
&all_fields, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list,
select_lex->leaf_tables, fields_list,
@@ -458,13 +459,6 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err; /* purecov: inspected */
}
}
-#ifdef NOT_NEEDED
- else if (!group_list && procedure->flags & PROC_GROUP)
- {
- my_message(ER_NO_GROUP_FOR_PROC, MYF(0));
- goto err;
- }
-#endif
if (order && (procedure->flags & PROC_NO_SORT))
{ /* purecov: inspected */
my_message(ER_ORDER_WITH_PROC, ER(ER_ORDER_WITH_PROC),
@@ -1004,11 +998,8 @@ JOIN::optimize()
*/
if (need_tmp || select_distinct || group_list || order)
{
- for (uint i_h = const_tables; i_h < tables; i_h++)
- {
- TABLE* table_h = join_tab[i_h].table;
- table_h->file->ha_retrieve_all_pk();
- }
+ for (uint i = const_tables; i < tables; i++)
+ join_tab[i].table->prepare_for_position();
}
DBUG_EXECUTE("info",TEST_join(this););
@@ -1075,7 +1066,7 @@ JOIN::optimize()
tmp_table_param.hidden_field_count= (all_fields.elements -
fields_list.elements);
- if (!(exec_tmp_table1 =
+ if (!(exec_tmp_table1=
create_tmp_table(thd, &tmp_table_param, all_fields,
((!simple_group && !procedure &&
!(test_flags & TEST_NO_KEY_GROUP)) ?
@@ -1791,9 +1782,7 @@ JOIN::destroy()
{
JOIN_TAB *tab, *end;
for (tab= join_tab, end= tab+tables ; tab != end ; tab++)
- {
tab->cleanup();
- }
}
tmp_join->tmp_join= 0;
tmp_table_param.copy_field=0;
@@ -2048,16 +2037,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
s->dependent= tables->dep_tables;
s->key_dependent= 0;
if (tables->schema_table)
- table->file->records= 2;
+ table->file->stats.records= 2;
s->on_expr_ref= &tables->on_expr;
if (*s->on_expr_ref)
{
/* s is the only inner table of an outer join */
#ifdef WITH_PARTITION_STORAGE_ENGINE
- if ((!table->file->records || table->no_partitions_used) && !embedding)
+ if ((!table->file->stats.records || table->no_partitions_used) && !embedding)
#else
- if (!table->file->records && !embedding)
+ if (!table->file->stats.records && !embedding)
#endif
{ // Empty table
s->dependent= 0; // Ignore LEFT JOIN depend.
@@ -2090,10 +2079,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
#else
const bool no_partitions_used= FALSE;
#endif
- if ((table->s->system || table->file->records <= 1 ||
+ if ((table->s->system || table->file->stats.records <= 1 ||
no_partitions_used) &&
!s->dependent &&
- !(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
+ (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
!table->fulltext_searched)
{
set_position(join,const_count++,s,(KEYUSE*) 0);
@@ -2182,8 +2171,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
// All dep. must be constants
if (s->dependent & ~(found_const_table_map))
continue;
- if (table->file->records <= 1L &&
- !(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
+ if (table->file->stats.records <= 1L &&
+ (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
!table->pos_in_table_list->embedding)
{ // system table
int tmp= 0;
@@ -2271,7 +2260,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
continue;
}
/* Approximate found rows and time to read them */
- s->found_records=s->records=s->table->file->records;
+ s->found_records=s->records=s->table->file->stats.records;
s->read_time=(ha_rows) s->table->file->scan_time();
/*
@@ -2581,7 +2570,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
bool is_const=1;
for (uint i=0; i<num_values; i++)
- is_const&= value[i]->const_item();
+ {
+ if (!(is_const&= value[i]->const_item()))
+ break;
+ }
if (is_const)
stat[0].const_keys.merge(possible_keys);
/*
@@ -3211,7 +3203,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
if (map == 1) // Only one table
{
TABLE *tmp_table=join->all_tables[tablenr];
- keyuse->ref_table_rows= max(tmp_table->file->records, 100);
+ keyuse->ref_table_rows= max(tmp_table->file->stats.records, 100);
}
}
/*
@@ -3256,7 +3248,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
if (join->group_list)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
- (*cur_group->item)->walk(&Item::collect_item_field_processor,
+ (*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
(byte*) &indexed_fields);
}
else if (join->select_distinct)
@@ -3265,7 +3257,8 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
List_iterator<Item> select_items_it(select_items);
Item *item;
while ((item= select_items_it++))
- item->walk(&Item::collect_item_field_processor, (byte*) &indexed_fields);
+ item->walk(&Item::collect_item_field_processor, 0,
+ (byte*) &indexed_fields);
}
else
return;
@@ -3521,7 +3514,7 @@ best_access_path(JOIN *join,
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
- uint keys_per_block= table->file->block_size/2/
+ uint keys_per_block= table->file->stats.block_size/2/
(keyinfo->key_length+table->file->ref_length)+1;
tmp= record_count*(tmp+keys_per_block-1)/keys_per_block;
}
@@ -3665,7 +3658,7 @@ best_access_path(JOIN *join,
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
- uint keys_per_block= table->file->block_size/2/
+ uint keys_per_block= table->file->stats.block_size/2/
(keyinfo->key_length+table->file->ref_length)+1;
tmp= record_count*(tmp+keys_per_block-1)/keys_per_block;
}
@@ -3719,7 +3712,7 @@ best_access_path(JOIN *join,
if ((records >= s->found_records || best > s->read_time) && // (1)
!(s->quick && best_key && s->quick->index == best_key->key && // (2)
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
- !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
+ !((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
! s->table->used_keys.is_clear_all() && best_key) && // (3)
!(s->table->force_index && best_key && !s->quick)) // (4)
{ // Check full join
@@ -4519,12 +4512,13 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
{
uint null_fields,blobs,fields,rec_length;
- null_fields=blobs=fields=rec_length=0;
-
Field **f_ptr,*field;
+ MY_BITMAP *read_set= join_tab->table->read_set;;
+
+ null_fields= blobs= fields= rec_length=0;
for (f_ptr=join_tab->table->field ; (field= *f_ptr) ; f_ptr++)
{
- if (field->query_id == thd->query_id)
+ if (bitmap_is_set(read_set, field->field_index))
{
uint flags=field->flags;
fields++;
@@ -4541,7 +4535,7 @@ static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
rec_length+=sizeof(my_bool);
if (blobs)
{
- uint blob_length=(uint) (join_tab->table->file->mean_rec_length-
+ uint blob_length=(uint) (join_tab->table->file->stats.mean_rec_length-
(join_tab->table->s->reclength- rec_length));
rec_length+=(uint) max(4,blob_length);
}
@@ -4832,8 +4826,12 @@ bool
store_val_in_field(Field *field,Item *item)
{
bool error;
- THD *thd= field->table->in_use;
+ TABLE *table= field->table;
+ THD *thd= table->in_use;
ha_rows cuted_fields=thd->cuted_fields;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
+ table->write_set);
+
/*
we should restore old value of count_cuted_fields because
store_val_in_field can be called from mysql_insert
@@ -4843,6 +4841,7 @@ store_val_in_field(Field *field,Item *item)
thd->count_cuted_fields= CHECK_FIELD_WARN;
error= item->save_in_field(field, 1);
thd->count_cuted_fields= old_count_cuted_fields;
+ dbug_tmp_restore_column_map(table->write_set, old_map);
return error || cuted_fields != thd->cuted_fields;
}
@@ -5180,7 +5179,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(1);
tmp->quick_fix_field();
cond_tab->select_cond= !cond_tab->select_cond ? tmp :
- new Item_cond_and(cond_tab->select_cond,tmp);
+ new Item_cond_and(cond_tab->select_cond,
+ tmp);
if (!cond_tab->select_cond)
DBUG_RETURN(1);
cond_tab->select_cond->quick_fix_field();
@@ -5485,7 +5485,6 @@ static void
make_join_readinfo(JOIN *join, uint options)
{
uint i;
-
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
bool sorted= 1;
DBUG_ENTER("make_join_readinfo");
@@ -8034,6 +8033,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
item->result_field= new_field;
else
new_field->field_name= name;
+ new_field->flags|= (org_field->flags & NO_DEFAULT_VALUE_FLAG);
if (org_field->maybe_null() || (item && item->maybe_null))
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
@@ -8174,6 +8174,7 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table)
in this array
from_field if field will be created using other field as example,
pointer example field will be written here
+ default_field If field has a default value field, store it here
group 1 if we are going to do a relative group by on result
modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
@@ -8192,11 +8193,13 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table)
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
+ Field **default_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field,
uint convert_blob_length)
{
+ Field *result;
Item::Type orig_type= type;
Item *orig_item= 0;
@@ -8214,8 +8217,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::SUM_FUNC_ITEM:
{
Item_sum *item_sum=(Item_sum*) item;
- Field *result= item_sum->create_tmp_field(group, table,
- convert_blob_length);
+ result= item_sum->create_tmp_field(group, table, convert_blob_length);
if (!result)
thd->fatal_error();
return result;
@@ -8225,7 +8227,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
{
Item_field *field= (Item_field*) item;
bool orig_modify= modify_item;
- Field *result;
if (orig_type == Item::REF_ITEM)
modify_item= 0;
/*
@@ -8259,6 +8260,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
convert_blob_length);
if (orig_type == Item::REF_ITEM && orig_modify)
((Item_ref*)orig_item)->set_result_field(result);
+ if (field->field->eq_def(result))
+ *default_field= field->field;
return result;
}
/* Fall through */
@@ -8281,16 +8284,39 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
DBUG_ASSERT(((Item_result_field*)item)->result_field);
*from_field= ((Item_result_field*)item)->result_field;
}
- return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 :
- copy_func), modify_item,
- convert_blob_length);
- case Item::TYPE_HOLDER:
+ return create_tmp_field_from_item(thd, item, table,
+ (make_copy_field ? 0 : copy_func),
+ modify_item, convert_blob_length);
+ case Item::TYPE_HOLDER:
return ((Item_type_holder *)item)->make_field_by_type(table);
default: // Dosen't have to be stored
return 0;
}
}
+/*
+ Set up column usage bitmaps for a temporary table
+
+ IMPLEMENTATION
+ For temporary tables, we need one bitmap with all columns set and
+ a tmp_set bitmap to be used by things like filesort.
+*/
+
+void setup_tmp_table_column_bitmaps(TABLE *table, byte *bitmaps)
+{
+ uint field_count= table->s->fields;
+ bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
+ FALSE);
+ bitmap_init(&table->tmp_set,
+ (my_bitmap_map*) (bitmaps+ bitmap_buffer_size(field_count)),
+ field_count, FALSE);
+ /* write_set and all_set are copies of read_set */
+ table->def_write_set= table->def_read_set;
+ table->s->all_set= table->def_read_set;
+ bitmap_set_all(&table->s->all_set);
+ table->default_column_bitmaps();
+}
+
/*
Create a temp table according to a field list.
@@ -8345,9 +8371,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bool use_packed_rows= 0;
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
char *tmpname,path[FN_REFLEN];
- byte *pos,*group_buff;
+ byte *pos, *group_buff, *bitmaps;
uchar *null_flags;
- Field **reg_field, **from_field;
+ Field **reg_field, **from_field, **default_field;
uint *blob_field;
Copy_field *copy=0;
KEY *keyinfo;
@@ -8357,9 +8383,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
uint total_uneven_bit_length= 0;
bool force_copy_fields= param->force_copy_fields;
DBUG_ENTER("create_tmp_table");
- DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
- (int) distinct, (int) save_sum_fields,
- (ulong) rows_limit,test(group)));
+ DBUG_PRINT("enter",
+ ("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
+ (int) distinct, (int) save_sum_fields,
+ (ulong) rows_limit,test(group)));
statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
@@ -8417,6 +8444,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
&table, sizeof(*table),
&share, sizeof(*share),
&reg_field, sizeof(Field*) * (field_count+1),
+ &default_field, sizeof(Field*) * (field_count),
&blob_field, sizeof(uint)*(field_count+1),
&from_field, sizeof(Field*)*field_count,
&copy_func, sizeof(*copy_func)*(copy_func_count+1),
@@ -8426,8 +8454,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
&param->start_recinfo,
sizeof(*param->recinfo)*(field_count*2+4),
&tmpname, (uint) strlen(path)+1,
- &group_buff, group && ! using_unique_constraint ?
- param->group_length : 0,
+ &group_buff, (group && ! using_unique_constraint ?
+ param->group_length : 0),
+ &bitmaps, bitmap_buffer_size(field_count)*2,
NullS))
{
bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
@@ -8446,6 +8475,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bzero((char*) table,sizeof(*table));
bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
+ bzero((char*) default_field, sizeof(Field*) * (field_count));
bzero((char*) from_field,sizeof(Field*)*field_count);
table->mem_root= own_root;
@@ -8514,7 +8544,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
Field *new_field=
create_tmp_field(thd, table, arg, arg->type(), &copy_func,
- tmp_from_field, group != 0,not_all_columns,
+ tmp_from_field, &default_field[fieldnr],
+ group != 0,not_all_columns,
distinct, 0,
param->convert_blob_length);
if (!new_field)
@@ -8523,12 +8554,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
reclength+=new_field->pack_length();
if (new_field->flags & BLOB_FLAG)
{
- *blob_field++= (uint) (reg_field - table->field);
+ *blob_field++= fieldnr;
blob_count++;
}
if (new_field->type() == FIELD_TYPE_BIT)
total_uneven_bit_length+= new_field->field_length & 7;
- new_field->field_index= (uint) (reg_field - table->field);
*(reg_field++)= new_field;
if (new_field->real_type() == MYSQL_TYPE_STRING ||
new_field->real_type() == MYSQL_TYPE_VARCHAR)
@@ -8548,8 +8578,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*/
(*argp)->maybe_null=1;
}
- new_field->query_id= thd->query_id;
- new_field->fieldnr= ++fieldnr;
+ new_field->field_index= fieldnr++;
}
}
}
@@ -8571,7 +8600,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
Field *new_field= (param->schema_table) ?
create_tmp_field_for_schema(thd, item, table) :
create_tmp_field(thd, table, item, type, &copy_func,
- tmp_from_field, group != 0,
+ tmp_from_field, &default_field[fieldnr],
+ group != 0,
!force_copy_fields &&
(not_all_columns || group !=0),
item->marker == 4, force_copy_fields,
@@ -8593,7 +8623,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
total_uneven_bit_length+= new_field->field_length & 7;
if (new_field->flags & BLOB_FLAG)
{
- *blob_field++= (uint) (reg_field - table->field);
+ *blob_field++= fieldnr;
blob_count++;
}
if (item->marker == 4 && item->maybe_null)
@@ -8601,10 +8631,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
group_null_items++;
new_field->flags|= GROUP_FLAG;
}
- new_field->query_id= thd->query_id;
- new_field->fieldnr= ++fieldnr;
- new_field->field_index= (uint) (reg_field - table->field);
- *(reg_field++) =new_field;
+ new_field->field_index= fieldnr++;
+ *(reg_field++)= new_field;
}
if (!--hidden_field_count)
{
@@ -8617,12 +8645,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
We need to update hidden_field_count as we may have stored group
functions with constant arguments
*/
- param->hidden_field_count= (uint) (reg_field - table->field);
+ param->hidden_field_count= fieldnr;
null_count= 0;
}
}
+ DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field));
DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
- field_count= (uint) (reg_field - table->field);
+ field_count= fieldnr;
+ *reg_field= 0;
*blob_field= 0; // End marker
share->fields= field_count;
@@ -8646,6 +8676,7 @@ 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
@@ -8683,6 +8714,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
copy_func[0]=0; // End marker
+ setup_tmp_table_column_bitmaps(table, bitmaps);
+
recinfo=param->start_recinfo;
null_flags=(uchar*) table->record[0];
pos=table->record[0]+ null_pack_length;
@@ -8739,6 +8772,34 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count+= (field->field_length & 7);
}
field->reset();
+
+ /*
+ Test if there is a default field value. The test for ->ptr is to skip
+ 'offset' fields generated by initalize_tables
+ */
+ if (default_field[i] && default_field[i]->ptr)
+ {
+ /*
+ default_field[i] is set only in the cases when 'field' can
+ inherit the default value that is defined for the field referred
+ by the Item_field object from which 'field' has been created.
+ */
+ my_ptrdiff_t diff;
+ Field *orig_field= default_field[i];
+ /* Get the value from default_values */
+ diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
+ orig_field->table->record[0]);
+ orig_field->move_field_offset(diff); // Points now at default_values
+ if (orig_field->is_real_null())
+ field->set_null();
+ else
+ {
+ field->set_notnull();
+ memcpy(field->ptr, orig_field->ptr, field->pack_length());
+ }
+ orig_field->move_field_offset(-diff); // Back to record[0]
+ }
+
if (from_field[i])
{ /* Not a table Item */
copy->set(field,from_field[i],save_sum_fields);
@@ -8919,8 +8980,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (open_tmp_table(table))
goto err;
- table->file->ha_set_all_bits_in_read_set();
- table->file->ha_set_all_bits_in_write_set();
thd->mem_root= mem_root_save;
DBUG_RETURN(table);
@@ -8966,22 +9025,28 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
uint record_length= 0;
uint null_count= 0; /* number of columns which may be null */
uint null_pack_length; /* NULL representation array length */
+ uint *blob_field;
+ byte *bitmaps;
+ TABLE *table;
TABLE_SHARE *share;
- /* Create the table and list of all fields */
- TABLE *table= (TABLE*) thd->calloc(sizeof(*table)+sizeof(*share));
- field= (Field**) thd->alloc((field_count + 1) * sizeof(Field*));
- if (!table || !field)
+
+ if (!multi_alloc_root(thd->mem_root,
+ &table, sizeof(*table),
+ &share, sizeof(*share),
+ &field, (field_count + 1) * sizeof(Field*),
+ &blob_field, (field_count+1) *sizeof(uint),
+ &bitmaps, bitmap_buffer_size(field_count)*2,
+ NullS))
return 0;
+ bzero(table, sizeof(*table));
+ bzero(share, sizeof(*share));
table->field= field;
- table->s= share= (TABLE_SHARE*) (table+1);
+ table->s= share;
+ share->blob_field= blob_field;
share->fields= field_count;
-
- if (!(share->blob_field= (uint*)thd->alloc((field_list.elements + 1) *
- sizeof(uint))))
- return 0;
-
share->blob_ptr_size= mi_portable_sizeof_char_ptr;
+ setup_tmp_table_column_bitmaps(table, bitmaps);
/* Create all fields and calculate the total length of record */
List_iterator_fast<create_field> it(field_list);
@@ -9268,8 +9333,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
To use start_bulk_insert() (which is new in 4.1) we need to find
all places where a corresponding end_bulk_insert() should be put.
*/
- table->file->info(HA_STATUS_VARIABLE); /* update table->file->records */
- new_table.file->start_bulk_insert(table->file->records);
+ table->file->info(HA_STATUS_VARIABLE); /* update table->file->stats.records */
+ new_table.file->ha_start_bulk_insert(table->file->stats.records);
#else
/* HA_EXTRA_WRITE_CACHE can stay until close, no need to disable it */
new_table.file->extra(HA_EXTRA_WRITE_CACHE);
@@ -9283,11 +9348,11 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
*/
while (!table->file->rnd_next(new_table.record[1]))
{
- if ((write_err=new_table.file->ha_write_row(new_table.record[1])))
+ if ((write_err= new_table.file->write_row(new_table.record[1])))
goto err;
}
/* copy row that filled HEAP table */
- if ((write_err=new_table.file->ha_write_row(table->record[0])))
+ if ((write_err=new_table.file->write_row(table->record[0])))
{
if (write_err != HA_ERR_FOUND_DUPP_KEY &&
write_err != HA_ERR_FOUND_DUPP_UNIQUE || !ignore_last_dupp_key_error)
@@ -9304,6 +9369,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
*table= new_table;
*table->s= share;
table->file->change_table_ptr(table, table->s);
+ table->use_all_columns();
if (save_proc_info)
thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ?
"Copying to tmp table on disk" : save_proc_info);
@@ -10134,7 +10200,7 @@ join_read_const(JOIN_TAB *tab)
if (table->status & STATUS_GARBAGE) // If first read
{
table->status= 0;
- if (cp_buffer_from_ref(tab->join->thd, &tab->ref))
+ if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
error=HA_ERR_KEY_NOT_FOUND;
else
{
@@ -10207,7 +10273,7 @@ join_read_always_key(JOIN_TAB *tab)
{
table->file->ha_index_init(tab->ref.key, tab->sorted);
}
- if (cp_buffer_from_ref(tab->join->thd, &tab->ref))
+ if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
return -1;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
@@ -10234,7 +10300,7 @@ join_read_last_key(JOIN_TAB *tab)
if (!table->file->inited)
table->file->ha_index_init(tab->ref.key, tab->sorted);
- if (cp_buffer_from_ref(tab->join->thd, &tab->ref))
+ if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
return -1;
if ((error=table->file->index_read_last(table->record[0],
tab->ref.key_buff,
@@ -10408,8 +10474,9 @@ join_ft_read_first(JOIN_TAB *tab)
if (!table->file->inited)
table->file->ha_index_init(tab->ref.key, 1);
#if NOT_USED_YET
- if (cp_buffer_from_ref(tab->join->thd, &tab->ref)) // as ft-key doesn't use store_key's
- return -1; // see also FT_SELECT::init()
+ /* as ft-key doesn't use store_key's, see also FT_SELECT::init() */
+ if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
+ return -1;
#endif
table->file->ft_init();
@@ -10516,7 +10583,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
&& !join->send_group_parts && !join->having && !jt->select_cond &&
!(jt->select && jt->select->quick) &&
- !(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
+ (jt->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
(jt->ref.key < 0))
{
/* Join over all rows in table; Return number of found rows */
@@ -10532,7 +10599,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
else
{
table->file->info(HA_STATUS_VARIABLE);
- join->send_records = table->file->records;
+ join->send_records= table->file->stats.records;
}
}
else
@@ -10708,7 +10775,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
int error;
join->found_records++;
- if ((error=table->file->ha_write_row(table->record[0])))
+ if ((error=table->file->write_row(table->record[0])))
{
if (error == HA_ERR_FOUND_DUPP_KEY ||
error == HA_ERR_FOUND_DUPP_UNIQUE)
@@ -10770,8 +10837,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{ /* Update old record */
restore_record(table,record[1]);
update_tmptable_sum_func(join->sum_funcs,table);
- if ((error=table->file->ha_update_row(table->record[1],
- table->record[0])))
+ if ((error=table->file->update_row(table->record[1],
+ table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
@@ -10794,7 +10861,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
init_tmptable_sum_functions(join->sum_funcs);
copy_funcs(join->tmp_table_param.items_to_copy);
- if ((error=table->file->ha_write_row(table->record[0])))
+ if ((error=table->file->write_row(table->record[0])))
{
if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
error, 0))
@@ -10830,7 +10897,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_fields(&join->tmp_table_param); // Groups are copied twice.
copy_funcs(join->tmp_table_param.items_to_copy);
- if (!(error=table->file->ha_write_row(table->record[0])))
+ if (!(error=table->file->write_row(table->record[0])))
join->send_records++; // New group
else
{
@@ -10839,15 +10906,15 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
table->file->print_error(error,MYF(0)); /* purecov: inspected */
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
- if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
+ if (table->file->rnd_pos(table->record[1],table->file->dup_ref))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
restore_record(table,record[1]);
update_tmptable_sum_func(join->sum_funcs,table);
- if ((error=table->file->ha_update_row(table->record[1],
- table->record[0])))
+ if ((error=table->file->update_row(table->record[1],
+ table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
@@ -10890,7 +10957,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->sum_funcs_end[send_group_parts]);
if (!join->having || join->having->val_int())
{
- int error= table->file->ha_write_row(table->record[0]);
+ int error= table->file->write_row(table->record[0]);
if (error && create_myisam_from_heap(join->thd, table,
&join->tmp_table_param,
error, 0))
@@ -11387,6 +11454,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (!select->quick->reverse_sorted())
{
+ QUICK_SELECT_DESC *tmp;
int quick_type= select->quick->get_type();
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
@@ -11395,8 +11463,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
DBUG_RETURN(0); // Use filesort
/* ORDER BY range_key DESC */
- QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
- used_key_parts);
+ tmp= new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
+ used_key_parts);
if (!tmp || tmp->error)
{
delete tmp;
@@ -11436,7 +11504,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
resolved with a key; This is because filesort() is usually faster than
retrieving all rows through an index.
*/
- if (select_limit >= table->file->records)
+ if (select_limit >= table->file->stats.records)
{
keys= *table->file->keys_to_use_for_scanning();
keys.merge(table->used_keys);
@@ -11577,7 +11645,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
if (table->s->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
table->sort.found_records=filesort(thd, table,sortorder, length,
- select, filesort_limit, &examined_rows);
+ select, filesort_limit, 0,
+ &examined_rows);
tab->records= table->sort.found_records; // For SQL_CALC_ROWS
if (select)
{
@@ -11711,7 +11780,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
entry->file->info(HA_STATUS_VARIABLE);
if (entry->s->db_type == &heap_hton ||
(!entry->s->blob_fields &&
- ((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->records <
+ ((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->stats.records <
thd->variables.sortbuff_size)))
error=remove_dup_with_hash_index(join->thd, entry,
field_count, first_field,
@@ -11758,7 +11827,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
}
if (having && !having->val_int())
{
- if ((error=file->ha_delete_row(record)))
+ if ((error=file->delete_row(record)))
goto err;
error=file->rnd_next(record);
continue;
@@ -11785,7 +11854,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
}
if (compare_record(table, first_field) == 0)
{
- if ((error=file->ha_delete_row(record)))
+ if ((error=file->delete_row(record)))
goto err;
}
else if (!found)
@@ -11832,7 +11901,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
if (!my_multi_malloc(MYF(MY_WME),
&key_buffer,
(uint) ((key_length + extra_length) *
- (long) file->records),
+ (long) file->stats.records),
&field_lengths,
(uint) (field_count*sizeof(*field_lengths)),
NullS))
@@ -11854,7 +11923,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
extra_length= ALIGN_SIZE(key_length)-key_length;
}
- if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0,
+ if (hash_init(&hash, &my_charset_bin, (uint) file->stats.records, 0,
key_length, (hash_get_key) 0, 0, 0))
{
my_free((char*) key_buffer,MYF(0));
@@ -11882,7 +11951,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
}
if (having && !having->val_int())
{
- if ((error=file->ha_delete_row(record)))
+ if ((error=file->delete_row(record)))
goto err;
continue;
}
@@ -11899,7 +11968,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
if (hash_search(&hash, org_key_pos, key_length))
{
/* Duplicated found ; Remove the row */
- if ((error=file->ha_delete_row(record)))
+ if ((error=file->delete_row(record)))
goto err;
}
else
@@ -12002,14 +12071,14 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
for (i=0 ; i < table_count ; i++)
{
uint null_fields=0,used_fields;
-
Field **f_ptr,*field;
+ MY_BITMAP *read_set= tables[i].table->read_set;
for (f_ptr=tables[i].table->field,used_fields=tables[i].used_fields ;
used_fields ;
f_ptr++)
{
field= *f_ptr;
- if (field->query_id == thd->query_id)
+ if (bitmap_is_set(read_set, field->field_index))
{
used_fields--;
length+=field->fill_cache_field(copy);
@@ -12208,7 +12277,8 @@ cmp_buffer_with_ref(JOIN_TAB *tab)
{
memcpy(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length);
}
- if ((tab->ref.key_err= cp_buffer_from_ref(tab->join->thd, &tab->ref)) ||
+ if ((tab->ref.key_err= cp_buffer_from_ref(tab->join->thd, tab->table,
+ &tab->ref)) ||
diff)
return 1;
return memcmp(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length)
@@ -12217,20 +12287,24 @@ cmp_buffer_with_ref(JOIN_TAB *tab)
bool
-cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
+cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{
enum enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
+ bool result= 0;
+
for (store_key **copy=ref->key_copy ; *copy ; copy++)
{
if ((*copy)->copy() & 1)
{
- thd->count_cuted_fields= save_count_cuted_fields;
- return 1; // Something went wrong
+ result= 1;
+ break;
}
}
thd->count_cuted_fields= save_count_cuted_fields;
- return 0;
+ dbug_tmp_restore_column_map(table->write_set, old_map);
+ return result;
}
@@ -12280,6 +12354,8 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item::Type order_item_type;
Item **select_item; /* The corresponding item from the SELECT clause. */
Field *from_field; /* The corresponding field from the FROM clause. */
+ uint counter;
+ bool unaliased;
/*
Local SP variables may be int but are expressions, not positions.
@@ -12301,8 +12377,6 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
return FALSE;
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
- uint counter;
- bool unaliased;
select_item= find_item_in_list(order_item, fields, &counter,
REPORT_EXCEPT_NOT_FOUND, &unaliased);
if (!select_item)
@@ -12514,11 +12588,11 @@ setup_new_fields(THD *thd, List<Item> &fields,
List<Item> &all_fields, ORDER *new_field)
{
Item **item;
- DBUG_ENTER("setup_new_fields");
-
- thd->set_query_id=1; // Not really needed, but...
uint counter;
bool not_used;
+ DBUG_ENTER("setup_new_fields");
+
+ thd->mark_used_columns= MARK_COLUMNS_READ; // Not really needed, but...
for (; new_field ; new_field= new_field->next)
{
if ((item= find_item_in_list(*new_field->item, fields, &counter,
@@ -13746,7 +13820,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table)
item->save_in_result_field(1);
}
copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
- if ((error= table->file->ha_write_row(table->record[0])))
+ if ((error= table->file->write_row(table->record[0])))
{
if (create_myisam_from_heap(thd, table, &tmp_table_param,
error, 0))
@@ -13804,6 +13878,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
join->unit->offset_limit_cnt= 0;
+ /*
+ NOTE: the number/types of items pushed into item_list must be in sync with
+ EXPLAIN column types as they're "defined" in THD::send_explain_fields()
+ */
if (message)
{
item_list.push_back(new Item_int((int32)
@@ -13943,11 +14021,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (!table->derived_select_number &&
(part_info= table->part_info))
{
- char parts_buff[128];
- String parts_str(parts_buff,sizeof(parts_buff),cs);
- make_used_partitions_str(part_info, &parts_str);
- item_list.push_back(new Item_string(parts_str.ptr(),
- parts_str.length(), cs));
+ Item_string *item_str= new Item_string(cs);
+ make_used_partitions_str(part_info, &item_str->str_value);
+ item_list.push_back(item_str);
}
else
item_list.push_back(item_null);
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 459d2ff89a8..6292977c209 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -56,16 +56,16 @@ typedef struct st_table_ref
*/
key_part_map null_rejecting;
table_map depend_map; // Table depends on these tables.
- byte *null_ref_key; // null byte position in the key_buf.
- // used for REF_OR_NULL optimization.
+ /* null byte position in the key_buf. Used for REF_OR_NULL optimization */
+ byte *null_ref_key;
} TABLE_REF;
+
/*
-** CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
-** table
+ CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
+ table
*/
-
typedef struct st_cache_field {
char *str;
uint length,blob_length;
@@ -83,7 +83,7 @@ typedef struct st_join_cache {
/*
-** The structs which holds the join connections and join states
+ The structs which holds the join connections and join states
*/
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
@@ -103,6 +103,7 @@ typedef enum_nested_loop_state
typedef int (*Read_record_func)(struct st_join_table *tab);
Next_select_func setup_end_select_func(JOIN *join);
+
typedef struct st_join_table {
st_join_table() {} /* Remove gcc warning */
TABLE *table;
@@ -482,7 +483,11 @@ class store_key_field: public store_key
}
enum store_key_result copy()
{
+ TABLE *table= copy_field.to_field->table;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
+ table->write_set);
copy_field.do_copy(&copy_field);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK;
}
const char *name() const { return field_name; }
@@ -502,7 +507,11 @@ public:
{}
enum store_key_result copy()
{
+ TABLE *table= to_field->table;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
+ table->write_set);
int res= item->save_in_field(to_field, 1);
+ dbug_tmp_restore_column_map(table->write_set, old_map);
return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res);
}
@@ -539,7 +548,7 @@ public:
const char *name() const { return "const"; }
};
-bool cp_buffer_from_ref(THD *thd, TABLE_REF *ref);
+bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 28bedf62ea5..83f64e2c9c9 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -25,6 +25,7 @@
#include "sp_head.h"
#include "sql_trigger.h"
#include "authors.h"
+#include "contributors.h"
#include "event.h"
#include <my_dir.h>
@@ -46,7 +47,7 @@ static void store_key_options(THD *thd, String *packet, TABLE *table,
KEY *key_info);
/***************************************************************************
-** List all table types supported
+** List all table types supported
***************************************************************************/
static my_bool show_handlerton(THD *thd, st_plugin_int *plugin,
@@ -54,25 +55,26 @@ static my_bool show_handlerton(THD *thd, st_plugin_int *plugin,
{
handlerton *default_type= (handlerton *) arg;
Protocol *protocol= thd->protocol;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if (!(hton->flags & HTON_HIDDEN))
{
protocol->prepare_for_resend();
- protocol->store(hton->name, system_charset_info);
+ protocol->store(plugin->name.str, plugin->name.length,
+ system_charset_info);
const char *option_name= show_comp_option_name[(int) hton->state];
if (hton->state == SHOW_OPTION_YES && default_type == hton)
option_name= "DEFAULT";
protocol->store(option_name, system_charset_info);
- protocol->store(hton->comment, system_charset_info);
+ protocol->store(plugin->plugin->descr, system_charset_info);
protocol->store(hton->commit ? "YES" : "NO", system_charset_info);
protocol->store(hton->prepare ? "YES" : "NO", system_charset_info);
protocol->store(hton->savepoint_set ? "YES" : "NO", system_charset_info);
-
+
return protocol->write() ? 1 : 0;
}
- return 0;
+ return 0;
}
bool mysqld_show_storage_engines(THD *thd)
@@ -92,7 +94,7 @@ bool mysqld_show_storage_engines(THD *thd)
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
- if (plugin_foreach(thd, show_handlerton,
+ if (plugin_foreach(thd, show_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, thd->variables.table_type))
DBUG_RETURN(TRUE);
@@ -229,6 +231,41 @@ bool mysqld_show_authors(THD *thd)
DBUG_RETURN(FALSE);
}
+
+/***************************************************************************
+** List all Contributors.
+** Please get permission before updating
+***************************************************************************/
+
+bool mysqld_show_contributors(THD *thd)
+{
+ List<Item> field_list;
+ Protocol *protocol= thd->protocol;
+ DBUG_ENTER("mysqld_show_contributors");
+
+ field_list.push_back(new Item_empty_string("Name",40));
+ field_list.push_back(new Item_empty_string("Location",40));
+ field_list.push_back(new Item_empty_string("Comment",80));
+
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ show_table_contributors_st *contributors;
+ for (contributors= show_table_contributors; contributors->name; contributors++)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(contributors->name, system_charset_info);
+ protocol->store(contributors->location, system_charset_info);
+ protocol->store(contributors->comment, system_charset_info);
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
+ }
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
+}
+
+
/***************************************************************************
List all privileges supported
***************************************************************************/
@@ -704,6 +741,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
field_list.push_back(new Item_field(field));
}
restore_record(table, s->default_values); // Get empty record
+ table->use_all_columns();
if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
Protocol::SEND_EOF))
DBUG_VOID_RETURN;
@@ -917,9 +955,9 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
RETURN
0 OK
*/
-int
-store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
- HA_CREATE_INFO *create_info_arg)
+
+int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
+ HA_CREATE_INFO *create_info_arg)
{
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, uname[NAME_LEN*3+1];
@@ -941,6 +979,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
MODE_MYSQL323 |
MODE_MYSQL40)) != 0;
+ my_bitmap_map *old_map;
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
@@ -963,6 +1002,12 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
append_identifier(thd, packet, alias, strlen(alias));
packet->append(STRING_WITH_LEN(" (\n"));
+ /*
+ We need this to get default values from the table
+ We have to restore the read_set if we are called from insert in case
+ of row based replication.
+ */
+ old_map= tmp_use_all_columns(table, table->read_set);
for (ptr=table->field ; (field= *ptr); ptr++)
{
@@ -1117,10 +1162,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
{
+ char *end;
buff[0] = '(';
- char* end=int10_to_str((long) key_part->length /
- key_part->field->charset()->mbmaxlen,
- buff + 1,10);
+ end= int10_to_str((long) key_part->length /
+ key_part->field->charset()->mbmaxlen,
+ buff + 1,10);
*end++ = ')';
packet->append(buff,(uint) (end-buff));
}
@@ -1289,13 +1335,14 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
(!table->part_info->is_auto_partitioned) &&
((part_syntax= generate_partition_syntax(table->part_info,
&part_syntax_len,
- FALSE,FALSE))))
+ FALSE))))
{
packet->append(part_syntax, part_syntax_len);
my_free(part_syntax, MYF(0));
}
}
#endif
+ tmp_restore_column_map(table->read_set, old_map);
DBUG_RETURN(0);
}
@@ -2339,7 +2386,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
SELECT_LEX *select_lex= &lex->select_lex;
SELECT_LEX *old_all_select_lex= lex->all_selects_list;
- TABLE_LIST **save_query_tables_last= lex->query_tables_last;
enum_sql_command save_sql_command= lex->sql_command;
SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
@@ -2358,6 +2404,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
enum legacy_db_type not_used;
Open_tables_state open_tables_state_backup;
bool save_view_prepare_mode= lex->view_prepare_mode;
+ Query_tables_list query_tables_list_backup;
lex->view_prepare_mode= TRUE;
DBUG_ENTER("get_all_tables");
@@ -2370,6 +2417,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
+ lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
+
/*
We should not introduce deadlocks even if we already have some
tables open and locked, since we won't lock tables which we will
@@ -2410,8 +2459,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
show_table_list->db),
show_table_list->alias));
thd->temporary_tables= 0;
- close_thread_tables(thd);
- show_table_list->table= 0;
+ close_tables_for_reopen(thd, &show_table_list);
goto err;
}
@@ -2503,8 +2551,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
int res;
/*
- Set the parent lex of 'sel' because it is needed by sel.init_query()
- which is called inside make_table_list.
+ Set the parent lex of 'sel' because it is needed by
+ sel.init_query() which is called inside make_table_list.
*/
sel.parent_lex= lex;
if (make_table_list(thd, &sel, base_name, file_name))
@@ -2522,9 +2570,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
in this case.
*/
res= schema_table->process_table(thd, show_table_list, table,
- res, base_name,
- show_table_list->alias);
- close_thread_tables(thd);
+ res, base_name,
+ show_table_list->alias);
+ close_tables_for_reopen(thd, &show_table_list);
+ DBUG_ASSERT(!lex->query_tables_own_last);
if (res)
goto err;
}
@@ -2541,11 +2590,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
error= 0;
err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
+ lex->restore_backup_query_tables_list(&query_tables_list_backup);
lex->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
- lex->query_tables_last= save_query_tables_last;
lex->view_prepare_mode= save_view_prepare_mode;
- *save_query_tables_last= 0;
lex->sql_command= save_sql_command;
DBUG_RETURN(error);
}
@@ -2699,50 +2747,55 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
case ROW_TYPE_COMPACT:
tmp_buff= "Compact";
break;
+ case ROW_TYPE_PAGES:
+ tmp_buff= "Paged";
+ break;
}
table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
if (!tables->schema_table)
{
- table->field[7]->store((longlong) file->records, TRUE);
+ table->field[7]->store((longlong) file->stats.records, TRUE);
table->field[7]->set_notnull();
}
- table->field[8]->store((longlong) file->mean_rec_length, TRUE);
- table->field[9]->store((longlong) file->data_file_length, TRUE);
- if (file->max_data_file_length)
+ table->field[8]->store((longlong) file->stats.mean_rec_length, TRUE);
+ table->field[9]->store((longlong) file->stats.data_file_length, TRUE);
+ if (file->stats.max_data_file_length)
{
- table->field[10]->store((longlong) file->max_data_file_length, TRUE);
+ table->field[10]->store((longlong) file->stats.max_data_file_length,
+ TRUE);
}
- table->field[11]->store((longlong) file->index_file_length, TRUE);
- table->field[12]->store((longlong) file->delete_length, TRUE);
+ table->field[11]->store((longlong) file->stats.index_file_length, TRUE);
+ table->field[12]->store((longlong) file->stats.delete_length, TRUE);
if (show_table->found_next_number_field)
{
- table->field[13]->store((longlong) file->auto_increment_value, TRUE);
+ table->field[13]->store((longlong) file->stats.auto_increment_value,
+ TRUE);
table->field[13]->set_notnull();
}
- if (file->create_time)
+ if (file->stats.create_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->create_time);
+ file->stats.create_time);
table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[14]->set_notnull();
}
- if (file->update_time)
+ if (file->stats.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->update_time);
+ file->stats.update_time);
table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[15]->set_notnull();
}
- if (file->check_time)
+ if (file->stats.check_time)
{
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time);
+ thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time);
table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[16]->set_notnull();
}
tmp_buff= (share->table_charset ?
share->table_charset->name : "default");
table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
- if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
{
table->field[18]->store((longlong) file->checksum(), TRUE);
table->field[18]->set_notnull();
@@ -2839,6 +2892,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
restore_record(show_table, s->default_values);
base_name_length= strlen(base_name);
file_name_length= strlen(file_name);
+ show_table->use_all_columns(); // Required for default
for (ptr=show_table->field; (field= *ptr) ; ptr++)
{
@@ -3055,7 +3109,7 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin,
void *ptable)
{
TABLE *table= (TABLE *) ptable;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
DBUG_ENTER("iter_schema_engines");
@@ -3063,21 +3117,26 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin,
if (!(hton->flags & HTON_HIDDEN))
{
if (!(wild && wild[0] &&
- wild_case_compare(scs, hton->name,wild)))
+ wild_case_compare(scs, plugin->name.str,wild)))
{
- const char *tmp;
+ LEX_STRING state[2]= {{(char*) STRING_WITH_LEN("ENABLED")},
+ {(char*) STRING_WITH_LEN("DISABLED")}};
+ LEX_STRING yesno[2]= {{(char*) STRING_WITH_LEN("NO")},
+ {(char*) STRING_WITH_LEN("YES")}};
+ LEX_STRING *tmp;
restore_record(table, s->default_values);
- table->field[0]->store(hton->name, strlen(hton->name), scs);
- tmp= hton->state ? "DISABLED" : "ENABLED";
- table->field[1]->store( tmp, strlen(tmp), scs);
- table->field[2]->store(hton->comment, strlen(hton->comment), scs);
- tmp= hton->commit ? "YES" : "NO";
- table->field[3]->store( tmp, strlen(tmp), scs);
- tmp= hton->prepare ? "YES" : "NO";
- table->field[4]->store( tmp, strlen(tmp), scs);
- tmp= hton->savepoint_set ? "YES" : "NO";
- table->field[5]->store( tmp, strlen(tmp), scs);
+ table->field[0]->store(plugin->name.str, plugin->name.length, scs);
+ tmp= &state[test(hton->state)];
+ table->field[1]->store(tmp->str, tmp->length, scs);
+ table->field[2]->store(plugin->plugin->descr,
+ strlen(plugin->plugin->descr), scs);
+ tmp= &yesno[test(hton->commit)];
+ table->field[3]->store(tmp->str, tmp->length, scs);
+ tmp= &yesno[test(hton->prepare)];
+ table->field[4]->store(tmp->str, tmp->length, scs);
+ tmp= &yesno[test(hton->savepoint_set)];
+ table->field[5]->store(tmp->str, tmp->length, scs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
@@ -3089,7 +3148,7 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin,
int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
{
- return plugin_foreach(thd, iter_schema_engines,
+ return plugin_foreach(thd, iter_schema_engines,
MYSQL_STORAGE_ENGINE_PLUGIN, tables->table);
}
@@ -3104,7 +3163,7 @@ int fill_schema_collation(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_HIDDEN) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
@@ -3346,7 +3405,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
KEY *key=show_table->key_info+i;
if (key->rec_per_key[j])
{
- ha_rows records=(show_table->file->records /
+ ha_rows records=(show_table->file->stats.records /
key->rec_per_key[j]);
table->field[9]->store((longlong) records, TRUE);
table->field[9]->set_notnull();
@@ -3391,11 +3450,33 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables,
if (tables->view)
{
+ Security_context *sctx= thd->security_ctx;
+ ulong grant= SHOW_VIEW_ACL;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ char *save_table_name= tables->table_name;
+ if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
+ sctx->priv_user) &&
+ !my_strcasecmp(system_charset_info, tables->definer.host.str,
+ sctx->priv_host))
+ grant= SHOW_VIEW_ACL;
+ else
+ {
+ tables->table_name= tables->view_name.str;
+ if (check_access(thd, SHOW_VIEW_ACL , base_name,
+ &tables->grant.privilege, 0, 1,
+ test(tables->schema_table)))
+ grant= get_table_grant(thd, tables);
+ else
+ grant= tables->grant.privilege;
+ }
+ tables->table_name= save_table_name;
+#endif
+
restore_record(table, s->default_values);
table->field[1]->store(tables->view_db.str, tables->view_db.length, cs);
- table->field[2]->store(tables->view_name.str, tables->view_name.length,
- cs);
- table->field[3]->store(tables->query.str, tables->query.length, cs);
+ table->field[2]->store(tables->view_name.str, tables->view_name.length, cs);
+ if (grant & SHOW_VIEW_ACL)
+ table->field[3]->store(tables->query.str, tables->query.length, cs);
if (tables->with_check != VIEW_CHECK_NONE)
{
@@ -3751,7 +3832,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *table,
table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[20]->set_notnull();
}
- if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
{
table->field[21]->store((longlong) stat_info.check_sum, TRUE);
table->field[21]->set_notnull();
@@ -3853,24 +3934,28 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
{
table->field[9]->store(part_info->part_func_string,
part_info->part_func_len, cs);
- table->field[9]->set_notnull();
}
else if (part_info->list_of_part_fields)
{
collect_partition_expr(part_info->part_field_list, &tmp_str);
table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
- table->field[9]->set_notnull();
}
+ table->field[9]->set_notnull();
if (part_info->is_sub_partitioned())
{
/* Subpartition method */
+ tmp_res.length(0);
+ if (part_info->linear_hash_ind)
+ tmp_res.append(partition_keywords[PKW_LINEAR].str,
+ partition_keywords[PKW_LINEAR].length);
if (part_info->list_of_subpart_fields)
- table->field[8]->store(partition_keywords[PKW_KEY].str,
- partition_keywords[PKW_KEY].length, cs);
+ tmp_res.append(partition_keywords[PKW_KEY].str,
+ partition_keywords[PKW_KEY].length);
else
- table->field[8]->store(partition_keywords[PKW_HASH].str,
- partition_keywords[PKW_HASH].length, cs);
+ 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();
/* Subpartition expression */
@@ -3878,14 +3963,13 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
{
table->field[10]->store(part_info->subpart_func_string,
part_info->subpart_func_len, cs);
- table->field[10]->set_notnull();
}
else if (part_info->list_of_subpart_fields)
{
collect_partition_expr(part_info->subpart_field_list, &tmp_str);
table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
- table->field[10]->set_notnull();
}
+ table->field[10]->set_notnull();
}
while ((part_elem= part_it++))
@@ -4020,8 +4104,24 @@ static interval_type get_real_interval_type(interval_type i_type)
extern LEX_STRING interval_type_to_name[];
+
+/*
+ Loads an event from mysql.event and copies it's data to a row of
+ I_S.EVENTS
+
+ Synopsis
+ copy_event_to_schema_table()
+ thd Thread
+ sch_table The schema table (information_schema.event)
+ event_table The event table to use for loading (mysql.event).
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
static int
-fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
+copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
@@ -4039,9 +4139,19 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
DBUG_RETURN(0);
-
+
+ /*
+ Skip events in schemas one does not have access to. The check is
+ optimized. It's guaranteed in case of SHOW EVENTS that the user
+ has access.
+ */
+ if (thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS &&
+ check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1,
+ is_schema_db(et.dbname.str)))
+ DBUG_RETURN(0);
+
/* ->field[0] is EVENT_CATALOG and is by default NULL */
-
+
sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs);
sch_table->field[2]->store(et.name.str, et.name.length, scs);
sch_table->field[3]->store(et.definer.str, et.definer.length, scs);
@@ -4053,28 +4163,28 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
ulong sql_mode_len=0;
sql_mode_str=
sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
- &sql_mode_len);
+ &sql_mode_len);
sch_table->field[9]->store((const char*)sql_mode_str, sql_mode_len, scs);
}
-
+
if (et.expression)
{
String show_str;
/* type */
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
- if (event_reconstruct_interval_expression(&show_str, et.interval,
- et.expression))
+ if (Events::reconstruct_interval_expression(&show_str, et.interval,
+ et.expression))
DBUG_RETURN(1);
sch_table->field[7]->set_notnull();
- sch_table->field[7]->store(show_str.c_ptr(), show_str.length(), scs);
+ sch_table->field[7]->store(show_str.ptr(), show_str.length(), scs);
LEX_STRING *ival= &interval_type_to_name[et.interval];
sch_table->field[8]->set_notnull();
sch_table->field[8]->store(ival->str, ival->length, scs);
- //starts & ends
+ /* starts & ends */
sch_table->field[10]->set_notnull();
sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
@@ -4093,14 +4203,14 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
}
- //status
- if (et.status == MYSQL_EVENT_ENABLED)
+ /* status */
+ if (et.status == Event_timed::ENABLED)
sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs);
else
sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs);
- //on_completion
- if (et.on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
+ /* on_completion */
+ if (et.on_completion == Event_timed::ON_COMPLETION_DROP)
sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs);
else
sch_table->field[13]->store(STRING_WITH_LEN("PRESERVE"), scs);
@@ -4129,100 +4239,179 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
}
-int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond)
+/*
+ Performs an index scan of event_table (mysql.event) and fills schema_table.
+
+ Synopsis
+ events_table_index_read_for_db()
+ thd Thread
+ schema_table The I_S.EVENTS table
+ event_table The event table to use for loading (mysql.event)
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
+static
+int events_table_index_read_for_db(THD *thd, TABLE *schema_table,
+ TABLE *event_table)
{
- TABLE *table= tables->table;
- CHARSET_INFO *scs= system_charset_info;
- TABLE *event_table= NULL;
- Open_tables_state backup;
int ret=0;
- bool verbose= false;
- char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
- bool use_prefix_scanning= true;
- uint key_len= 0;
+ CHARSET_INFO *scs= system_charset_info;
+ KEY *key_info;
+ uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
- DBUG_ENTER("fill_schema_events");
-
- strxmov(definer, thd->security_ctx->priv_user,"@",thd->security_ctx->priv_host,
- NullS);
+ DBUG_ENTER("schema_events_do_index_scan");
- DBUG_PRINT("info",("db=%s current_user=%s", thd->lex->select_lex.db, definer));
-
- thd->reset_n_backup_open_tables_state(&backup);
+ DBUG_PRINT("info", ("Using prefix scanning on PK"));
+ event_table->file->ha_index_init(0, 1);
+ event_table->field[Events::FIELD_DB]->
+ store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
+ key_info= event_table->key_info;
+ key_len= key_info->key_part[0].store_length;
- if ((ret= evex_open_event_table(thd, TL_READ, &event_table)))
+ if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
- sql_print_error("Table mysql.event is damaged.");
ret= 1;
- goto err;
- }
-
- event_table->file->ha_index_init(0, 1);
-
- /*
- see others' events only if you have PROCESS_ACL !!
- thd->lex->verbose is set either if SHOW FULL EVENTS or
- in case of SELECT FROM I_S.EVENTS
- */
- verbose= (thd->lex->verbose
- && (thd->security_ctx->master_access & PROCESS_ACL));
-
- if (verbose && thd->security_ctx->user)
- {
- ret= event_table->file->index_first(event_table->record[0]);
- use_prefix_scanning= false;
+ /* don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
- event_table->field[EVEX_FIELD_DEFINER]->store(definer, strlen(definer), scs);
- key_len= event_table->key_info->key_part[0].store_length;
-
- if (thd->lex->select_lex.db)
- {
- event_table->field[EVEX_FIELD_DB]->
- store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
- key_len+= event_table->key_info->key_part[1].store_length;
- }
- if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
+ key_copy(key_buf, event_table->record[0], key_info, key_len);
+ if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
+ key_len, HA_READ_PREFIX)))
{
- ret= 1;
- goto err;
+ DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
+ do
+ {
+ ret= copy_event_to_schema_table(thd, schema_table, event_table);
+ if (ret == 0)
+ ret= event_table->file->index_next_same(event_table->record[0],
+ key_buf, key_len);
+ } while (ret == 0);
}
-
- key_copy(key_buf, event_table->record[0], event_table->key_info, key_len);
- ret= event_table->file->index_read(event_table->record[0], key_buf, key_len,
- HA_READ_PREFIX);
+ DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
}
+ event_table->file->ha_index_end();
+ /* ret is guaranteed to be != 0 */
+ if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(0);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Performs a table scan of event_table (mysql.event) and fills schema_table.
+
+ Synopsis
+ events_table_scan_all()
+ thd Thread
+ schema_table The I_S.EVENTS in memory table
+ event_table The event table to use for loading.
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
+static
+int events_table_scan_all(THD *thd, TABLE *schema_table,
+ TABLE *event_table)
+{
+ int ret;
+ READ_RECORD read_record_info;
- if (ret)
+ DBUG_ENTER("schema_events_do_table_scan");
+ init_read_record(&read_record_info, thd, event_table, NULL, 1, 0);
+
+ /*
+ rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
+ but rr_handle_error returns -1 for that reason. Thus, read_record()
+ returns -1 eventually.
+ */
+ do
{
- ret= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1;
- goto err;
+ ret= read_record_info.read_record(&read_record_info);
+ if (ret == 0)
+ ret= copy_event_to_schema_table(thd, schema_table, event_table);
}
+ while (ret == 0);
- while (!ret)
- {
- if ((ret= fill_events_copy_to_schema_table(thd, table, event_table)))
- goto err;
+ DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
+ end_read_record(&read_record_info);
- if (use_prefix_scanning)
- ret= event_table->file->
- index_next_same(event_table->record[0], key_buf, key_len);
- else
- ret= event_table->file->index_next(event_table->record[0]);
+ /* ret is guaranteed to be != 0 */
+ DBUG_RETURN(ret == -1? 0:1);
+}
+
+
+/*
+ Fills I_S.EVENTS with data loaded from mysql.event. Also used by
+ SHOW EVENTS
+
+ Synopsis
+ fill_schema_events()
+ thd Thread
+ tables The schema table
+ cond Unused
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
+int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
+{
+ TABLE *schema_table= tables->table;
+ TABLE *event_table= NULL;
+ Open_tables_state backup;
+ int ret= 0;
+
+ DBUG_ENTER("fill_schema_events");
+ /*
+ If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
+ be NULL. Let's do an assert anyway.
+ */
+ if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS)
+ {
+ DBUG_ASSERT(thd->lex->select_lex.db);
+ if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
+ is_schema_db(thd->lex->select_lex.db)))
+ DBUG_RETURN(1);
}
- // ret is guaranteed to be != 0
- ret= (ret != HA_ERR_END_OF_FILE);
-err:
- if (event_table)
+
+ DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db?
+ thd->lex->select_lex.db:"(null)"));
+
+ thd->reset_n_backup_open_tables_state(&backup);
+ if (Events::open_event_table(thd, TL_READ, &event_table))
{
- event_table->file->ha_index_end();
- close_thread_tables(thd);
+ sql_print_error("Table mysql.event is damaged.");
+ thd->restore_backup_open_tables_state(&backup);
+ DBUG_RETURN(1);
}
+ /*
+ 1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
+ thus we won't order it. OTOH, SHOW EVENTS will be
+ ordered.
+ 2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
+ Reasoning: Events are per schema, therefore a scan over an index
+ will save use from doing a table scan and comparing
+ every single row's `db` with the schema which we show.
+ */
+ if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS)
+ ret= events_table_index_read_for_db(thd, schema_table, event_table);
+ else
+ ret= events_table_scan_all(thd, schema_table, event_table);
+
+ close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
+
+ DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
@@ -4445,7 +4634,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
field_count++;
}
TMP_TABLE_PARAM *tmp_table_param =
- (TMP_TABLE_PARAM*) (thd->calloc(sizeof(TMP_TABLE_PARAM)));
+ (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
tmp_table_param->init();
tmp_table_param->table_charset= cs;
tmp_table_param->field_count= field_count;
@@ -4817,7 +5006,7 @@ bool get_schema_tables_result(JOIN *join)
filesort_free_buffers(table_list->table);
}
else
- table_list->table->file->records= 0;
+ table_list->table->file->stats.records= 0;
if (table_list->schema_table->fill_table(thd, table_list,
tab->select_cond))
@@ -4840,7 +5029,7 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin,
{
struct run_hton_fill_schema_files_args *args=
(run_hton_fill_schema_files_args *) arg;
- handlerton *hton= (handlerton *) plugin->plugin->info;
+ handlerton *hton= (handlerton *)plugin->data;
if(hton->fill_files_table)
hton->fill_files_table(thd, args->tables, args->cond);
return false;
@@ -5184,7 +5373,7 @@ ST_FIELD_INFO partitions_fields_info[]=
{"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
{"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
{"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0},
- {"SUBPARTITION_METHOD", 5, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0},
{"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
@@ -5259,9 +5448,9 @@ ST_FIELD_INFO files_fields_info[]=
{"FREE_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0},
{"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0},
{"EXTENT_SIZE", 4, MYSQL_TYPE_LONG, 0, 0, 0},
- {"INITIAL_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0},
- {"MAXIMUM_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0},
- {"AUTOEXTEND_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0},
+ {"INITIAL_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0},
+ {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0},
+ {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONG, 0, 0, 0},
{"CREATION_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0},
{"LAST_UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0},
{"LAST_ACCESS_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0},
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 0659f684afe..ddae6368228 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -24,8 +24,6 @@
#define NOT_FIXED_DEC 31
#endif
-#define STRING_WITH_LEN(X) ((const char*) X), ((uint) (sizeof(X) - 1))
-
class String;
int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f530af33e48..e9c89b4983d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -75,7 +75,9 @@ uint tablename_to_filename(const char *from, char *to, uint to_length)
uint errors, length;
if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX,
MYSQL50_TABLE_NAME_PREFIX_LENGTH))
- return my_snprintf(to, to_length, "%s", from + 9);
+ return (uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH,
+ to_length-1) -
+ (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH));
length= strconvert(system_charset_info, from,
&my_charset_filename, to, to_length, &errors);
if (check_if_legal_tablename(to) &&
@@ -1231,7 +1233,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE, FALSE)))
+ TRUE)))
{
DBUG_RETURN(TRUE);
}
@@ -2277,7 +2279,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (sql_field->sql_type == FIELD_TYPE_BIT)
{
sql_field->pack_flag= FIELDFLAG_NUMBER;
- if (file->table_flags() & HA_CAN_BIT_FIELD)
+ if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
total_uneven_bit_length+= sql_field->length & 7;
else
sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
@@ -2360,7 +2362,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (prepare_create_field(sql_field, &blob_columns,
&timestamps, &timestamps_with_niladic,
- file->table_flags()))
+ file->ha_table_flags()))
DBUG_RETURN(-1);
if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
create_info->varchar= 1;
@@ -2381,14 +2383,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
if (auto_increment &&
- (file->table_flags() & HA_NO_AUTO_INCREMENT))
+ (file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
{
my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
DBUG_RETURN(-1);
}
- if (blob_columns && (file->table_flags() & HA_NO_BLOBS))
+ if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
{
my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
MYF(0));
@@ -2545,7 +2547,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->type == Key::FULLTEXT)
{
- if (!(file->table_flags() & HA_CAN_FULLTEXT))
+ if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
{
my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
MYF(0));
@@ -2563,7 +2565,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* TODO: Add proper checks if handler supports key_type and algorithm */
if (key_info->flags & HA_SPATIAL)
{
- if (!(file->table_flags() & HA_CAN_RTREEKEYS))
+ if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
{
my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
MYF(0));
@@ -2665,7 +2667,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (f_is_blob(sql_field->pack_flag) ||
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
- if (!(file->table_flags() & HA_CAN_INDEX_BLOBS))
+ if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
{
my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
DBUG_RETURN(-1);
@@ -2702,22 +2704,24 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
null_fields--;
}
else
- key_info->flags|= HA_NULL_PART_KEY;
- if (!(file->table_flags() & HA_NULL_IN_KEY))
- {
- my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
- DBUG_RETURN(-1);
- }
- if (key->type == Key::SPATIAL)
- {
- my_message(ER_SPATIAL_CANT_HAVE_NULL,
- ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
- DBUG_RETURN(-1);
- }
+ {
+ key_info->flags|= HA_NULL_PART_KEY;
+ if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
+ {
+ my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
+ DBUG_RETURN(-1);
+ }
+ if (key->type == Key::SPATIAL)
+ {
+ my_message(ER_SPATIAL_CANT_HAVE_NULL,
+ ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
- if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY))
+ if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
auto_increment--; // Field is used
}
}
@@ -2754,14 +2758,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
else if (!f_is_geom(sql_field->pack_flag) &&
(column->length > length ||
((f_is_packed(sql_field->pack_flag) ||
- ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
+ ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
column->length != length)))
{
my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
DBUG_RETURN(-1);
}
- else if (!(file->table_flags() & HA_NO_PREFIX_CHAR_KEYS))
+ else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
length=column->length;
}
else if (length == 0)
@@ -2847,7 +2851,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
key_info++;
}
if (!unique_key && !primary_key &&
- (file->table_flags() & HA_REQUIRE_PRIMARY_KEY))
+ (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
{
my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
DBUG_RETURN(-1);
@@ -3053,8 +3057,8 @@ bool mysql_create_table_internal(THD *thd,
if (create_info->row_type == ROW_TYPE_DYNAMIC)
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)))
+ if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
+ create_info->db_type)))
{
mem_alloc_error(sizeof(handler));
DBUG_RETURN(TRUE);
@@ -3106,7 +3110,8 @@ bool mysql_create_table_internal(THD *thd,
}
while ((key= key_iterator++))
{
- if (key->type == Key::FOREIGN_KEY)
+ if (key->type == Key::FOREIGN_KEY &&
+ !part_info->is_auto_partitioned)
{
my_error(ER_CANNOT_ADD_FOREIGN, MYF(0));
goto err;
@@ -3150,7 +3155,7 @@ bool mysql_create_table_internal(THD *thd,
*/
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE, FALSE)))
+ TRUE)))
goto err;
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
@@ -3206,7 +3211,8 @@ bool mysql_create_table_internal(THD *thd,
engines in partition clauses.
*/
delete file;
- if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, engine_type)))
+ if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
+ engine_type)))
{
mem_alloc_error(sizeof(handler));
DBUG_RETURN(TRUE);
@@ -3456,7 +3462,7 @@ mysql_rename_table(handlerton *base,
a lowercase file name, but we leave the .frm in mixed case.
*/
if (lower_case_table_names == 2 && file &&
- !(file->table_flags() & HA_FILE_BASED))
+ !(file->ha_table_flags() & HA_FILE_BASED))
{
strmov(tmp_name, old_name);
my_casedn_str(files_charset_info, tmp_name);
@@ -3896,6 +3902,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
*/
ha_autocommit_or_rollback(thd, 1);
close_thread_tables(thd);
+ lex->reset_query_tables_list(FALSE);
if (protocol->write())
goto err;
continue;
@@ -3921,6 +3928,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
protocol->store(buff, length, system_charset_info);
ha_autocommit_or_rollback(thd, 0);
close_thread_tables(thd);
+ lex->reset_query_tables_list(FALSE);
table->table=0; // For query cache
if (protocol->write())
goto err;
@@ -4673,7 +4681,8 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
HA_CREATE_INFO *create_info,
ALTER_INFO *alter_info, uint order_num,
uint *index_drop_buffer, uint *index_drop_count,
- uint *index_add_buffer, uint *index_add_count)
+ uint *index_add_buffer, uint *index_add_count,
+ bool varchar)
{
Field **f_ptr, *field;
uint changes= 0, tmp;
@@ -4708,7 +4717,8 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
create_info->used_fields & HA_CREATE_USED_CHARSET ||
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
- order_num)
+ order_num ||
+ (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
/*
@@ -4738,7 +4748,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
if (!(tmp= field->is_equal(new_field)))
DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
// Clear indexed marker
- field->add_index= 0;
+ field->flags&= ~FIELD_IN_ADD_INDEX;
changes|= tmp;
}
@@ -4814,7 +4824,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
{
// Mark field to be part of new key
field= table->field[key_part->fieldnr];
- field->add_index= 1;
+ field->flags|= FIELD_IN_ADD_INDEX;
}
DBUG_PRINT("info", ("index changed: '%s'", table_key->name));
}
@@ -4841,7 +4851,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
{
// Mark field to be part of new key
field= table->field[key_part->fieldnr];
- field->add_index= 1;
+ field->flags|= FIELD_IN_ADD_INDEX;
}
DBUG_PRINT("info", ("index added: '%s'", new_key->name));
}
@@ -4882,7 +4892,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
uint db_create_options, used_fields;
handlerton *old_db_type, *new_db_type;
uint need_copy_table= 0;
- bool no_table_reopen= FALSE;
+ bool no_table_reopen= FALSE, varchar= FALSE;
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition= 0;
bool partition_changed= FALSE;
@@ -4924,6 +4934,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
alter_info->tablespace_op));
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(TRUE);
+ table->use_all_columns();
/* Check that we are not trying to rename to an existing table */
if (new_name)
@@ -4980,7 +4991,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
old_db_type= table->s->db_type;
- if (create_info->db_type == (handlerton*) &default_hton)
+ if (!create_info->db_type)
create_info->db_type= old_db_type;
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -5117,6 +5128,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Field **f_ptr,*field;
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
+ if (field->type() == MYSQL_TYPE_STRING)
+ varchar= TRUE;
/* Check if field should be dropped */
Alter_drop *drop;
drop_it.rewind();
@@ -5157,8 +5170,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
def_it.remove();
}
}
- else // This field was not dropped and not changed, add it to the list
- { // for the new table.
+ else
+ {
+ /*
+ This field was not dropped and not changed, add it to the list
+ for the new table.
+ */
create_list.push_back(def=new create_field(field,field));
alter_it.rewind(); // Change default if ALTER
Alter_column *alter;
@@ -5452,7 +5469,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
key_info_buffer, key_count,
create_info, alter_info, order_num,
index_drop_buffer, &index_drop_count,
- index_add_buffer, &index_add_count);
+ index_add_buffer, &index_add_count,
+ varchar);
}
/*
@@ -5670,7 +5688,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->proc_info="copy to tmp table";
next_insert_id=thd->next_insert_id; // Remember for logging
copied=deleted=0;
- if (new_table && !(new_table->file->table_flags() & HA_NO_COPY_ON_ALTER))
+ if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
{
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@@ -6134,7 +6152,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
MODE_STRICT_ALL_TABLES));
from->file->info(HA_STATUS_VARIABLE);
- to->file->start_bulk_insert(from->file->records);
+ to->file->ha_start_bulk_insert(from->file->stats.records);
save_sql_mode= thd->variables.sql_mode;
@@ -6180,19 +6198,14 @@ copy_data_between_tables(TABLE *from,TABLE *to,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(from->sort.found_records = filesort(thd, from, sortorder, length,
- (SQL_SELECT *) 0, HA_POS_ERROR,
+ (SQL_SELECT *) 0, HA_POS_ERROR, 1,
&examined_rows)) ==
HA_POS_ERROR)
goto err;
};
- /*
- Handler must be told explicitly to retrieve all columns, because
- this function does not set field->query_id in the columns to the
- current query id
- */
- to->file->ha_set_all_bits_in_write_set();
- from->file->ha_retrieve_all_cols();
+ /* 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);
if (ignore ||
handle_duplicates == DUP_REPLACE)
@@ -6227,6 +6240,21 @@ copy_data_between_tables(TABLE *from,TABLE *to,
(error != HA_ERR_FOUND_DUPP_KEY &&
error != HA_ERR_FOUND_DUPP_UNIQUE))
{
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ {
+ uint key_nr= to->file->get_dup_key(error);
+ if ((int) key_nr >= 0)
+ {
+ const char *err_msg= ER(ER_DUP_ENTRY);
+ if (key_nr == 0 &&
+ (to->key_info[0].key_part[0].field->flags &
+ AUTO_INCREMENT_FLAG))
+ err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
+ to->file->print_keydup_error(key_nr, err_msg);
+ break;
+ }
+ }
+
to->file->print_error(error,MYF(0));
break;
}
@@ -6240,7 +6268,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
free_io_cache(from);
delete [] copy; // This is never 0
- if (to->file->end_bulk_insert() && error <= 0)
+ if (to->file->ha_end_bulk_insert() && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
error=1;
@@ -6293,7 +6321,7 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
lex->col_list.empty();
lex->alter_info.reset();
bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= (handlerton*) &default_hton;
+ create_info.db_type= 0;
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
/* Force alter table to recreate table */
@@ -6345,10 +6373,10 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
{
t->pos_in_table_list= table;
- if (t->file->table_flags() & HA_HAS_CHECKSUM &&
+ if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
!(check_opt->flags & T_EXTEND))
protocol->store((ulonglong)t->file->checksum());
- else if (!(t->file->table_flags() & HA_HAS_CHECKSUM) &&
+ else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
(check_opt->flags & T_QUICK))
protocol->store_null();
else
@@ -6357,11 +6385,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
ha_checksum crc= 0;
uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
- /*
- Set all bits in read set and inform InnoDB that we are reading all
- fields
- */
- t->file->ha_retrieve_all_cols();
+ t->use_all_columns();
if (t->file->ha_rnd_init(1))
protocol->store_null();
@@ -6437,7 +6461,7 @@ static bool check_engine(THD *thd, const char *table_name,
no_substitution, 1)))
return TRUE;
- if (req_engine != (handlerton*) &default_hton && req_engine != *new_engine)
+ if (req_engine && req_engine != *new_engine)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
@@ -6450,7 +6474,8 @@ 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), (*new_engine)->name, "TEMPORARY");
+ my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
+ hton2plugin[(*new_engine)->slot]->name.str, "TEMPORARY");
*new_engine= 0;
return TRUE;
}
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index 8bc39ec82c6..94318a67575 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -28,16 +28,16 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
If the user haven't defined an engine, this will fallback to using the
default storage engine.
*/
- if (hton == NULL || hton == &default_hton || hton->state != SHOW_OPTION_YES)
+ if (hton == NULL || hton->state != SHOW_OPTION_YES)
{
hton= ha_resolve_by_legacy_type(thd, DB_TYPE_DEFAULT);
if (ts_info->storage_engine != 0)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- hton->name,
- ts_info->tablespace_name
- ? ts_info->tablespace_name : ts_info->logfile_group_name);
+ hton2plugin[hton->slot]->name.str,
+ ts_info->tablespace_name ? ts_info->tablespace_name
+ : ts_info->logfile_group_name);
}
if (hton->alter_tablespace)
@@ -64,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),
- hton->name,
+ hton2plugin[hton->slot]->name.str,
"TABLESPACE or LOGFILE GROUP");
}
if (mysql_bin_log.is_open())
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index b2b6b115f7d..0ea87f3dfe4 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1412,8 +1412,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
}
if (table.triggers)
{
- LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
- LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+ LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+ LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
/*
Since triggers should be in the same schema as their subject tables
moving table with them between two schemas raises too many questions.
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index b67c22e0588..bddfd8c1f0c 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -24,7 +24,7 @@
class Table_triggers_list: public Sql_alloc
{
/* Triggers as SPs grouped by event, action_time */
- sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
+ sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
/*
Copy of TABLE::Field array with field pointers set to TABLE::record[1]
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
@@ -132,6 +132,10 @@ private:
const char *db_name,
LEX_STRING *old_table_name,
LEX_STRING *new_table_name);
+ friend void st_table::mark_columns_needed_for_insert(void);
+ friend void st_table::mark_columns_needed_for_update(void);
+ friend void st_table::mark_columns_needed_for_delete(void);
+
};
extern const LEX_STRING trg_action_time_type_names[];
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 495ffe9f5d5..4b9de6905fe 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -152,7 +152,8 @@ void udf_init()
table= tables.table;
init_read_record(&read_record_info, new_thd, table, NULL,1,0);
- while (!(error = read_record_info.read_record(&read_record_info)))
+ table->use_all_columns();
+ while (!(error= read_record_info.read_record(&read_record_info)))
{
DBUG_PRINT("info",("init udf record"));
LEX_STRING name;
@@ -449,7 +450,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
/* Allow creation of functions even if we can't open func table */
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
-
+ table->use_all_columns();
restore_record(table, s->default_values); // Default values for fields
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
table->field[1]->store((longlong) u_d->returns, TRUE);
@@ -507,8 +508,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
tables.table_name= tables.alias= (char*) "func";
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
+ table->use_all_columns();
table->field[0]->store(udf_name->str, udf_name->length, system_charset_info);
- table->file->ha_retrieve_all_cols();
if (!table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr,
table->key_info[0].key_length,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 3c156acfc14..bf93f0d3bea 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -152,8 +152,8 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
order;
order=order->next)
{
- (*order->item)->walk(&Item::change_context_processor,
- (byte *) &fake_select_lex->context);
+ (*order->item)->walk(&Item::change_context_processor, 0,
+ (byte*) &fake_select_lex->context);
}
}
@@ -468,7 +468,7 @@ bool st_select_lex_unit::exec()
}
if (!res)
{
- records_at_start= table->file->records;
+ records_at_start= table->file->stats.records;
sl->join->exec();
if (sl == union_distinct)
{
@@ -507,7 +507,7 @@ bool st_select_lex_unit::exec()
rows and actual rows added to the temporary table.
*/
add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong)
- ((table->file->records - records_at_start)));
+ ((table->file->stats.records - records_at_start)));
}
}
}
@@ -567,7 +567,7 @@ bool st_select_lex_unit::exec()
fake_select_lex->table_list.empty();
if (!res)
{
- thd->limit_found_rows = (ulonglong)table->file->records + add_rows;
+ thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows;
thd->examined_row_count+= examined_rows;
}
/*
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 75e8db6621f..e917c1358ef 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -29,7 +29,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
/* Return 0 if row hasn't changed */
-static bool compare_record(TABLE *table, query_id_t query_id)
+static bool compare_record(TABLE *table)
{
if (table->s->blob_fields + table->s->varchar_fields == 0)
return cmp_record(table,record[1]);
@@ -39,9 +39,9 @@ static bool compare_record(TABLE *table, query_id_t query_id)
table->s->null_bytes))
return TRUE; // Diff in NULL value
/* Compare updated fields */
- for (Field **ptr=table->field ; *ptr ; ptr++)
+ for (Field **ptr= table->field ; *ptr ; ptr++)
{
- if ((*ptr)->query_id == query_id &&
+ if (bitmap_is_set(table->write_set, (*ptr)->field_index) &&
(*ptr)->cmp_binary_offset(table->s->rec_buff_length))
return TRUE;
}
@@ -120,6 +120,7 @@ int mysql_update(THD *thd,
bool using_limit= limit != HA_POS_ERROR;
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
bool used_key_is_modified, transactional_table, will_batch;
+ bool can_compare_record;
int res;
int error, loc_error;
uint used_index= MAX_KEY, dup_key_found;
@@ -128,7 +129,6 @@ int mysql_update(THD *thd,
uint want_privilege;
#endif
uint table_count= 0;
- query_id_t query_id=thd->query_id, timestamp_query_id;
ha_rows updated, found;
key_map old_used_keys;
TABLE *table;
@@ -138,8 +138,6 @@ int mysql_update(THD *thd,
bool need_reopen;
DBUG_ENTER("mysql_update");
- LINT_INIT(timestamp_query_id);
-
for ( ; ; )
{
if (open_tables(thd, &table_list, &table_count, 0))
@@ -181,26 +179,12 @@ int mysql_update(THD *thd,
DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE
- /*
- Change the query_id for the timestamp column so that we can
- check if this is modified directly
- */
- if (table->timestamp_field)
- {
- timestamp_query_id=table->timestamp_field->query_id;
- table->timestamp_field->query_id=thd->query_id-1;
- }
-
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
table_list->register_want_access(want_privilege);
#endif
- /*
- Indicate that the set of fields is to be updated by passing 2 for
- set_query_id.
- */
- if (setup_fields_with_no_wrap(thd, 0, fields, 2, 0, 0))
+ if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(1); /* purecov: inspected */
if (table_list->view && check_fields(thd, fields))
{
@@ -214,12 +198,13 @@ int mysql_update(THD *thd,
if (table->timestamp_field)
{
// Don't set timestamp column if this is modified
- if (table->timestamp_field->query_id == thd->query_id)
+ if (bitmap_is_set(table->write_set,
+ table->timestamp_field->field_index))
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
else
{
- table->timestamp_field->query_id=timestamp_query_id;
- table->file->ha_set_bit_in_write_set(table->timestamp_field->fieldnr);
+ bitmap_set_bit(table->write_set,
+ table->timestamp_field->field_index);
}
}
@@ -228,7 +213,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, 0, values, 1, 0, 0))
+ if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -252,7 +237,7 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
#endif
- /* Update the table->file->records number */
+ /* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
select= make_select(table, 0, 0, conds, 0, &error);
@@ -313,19 +298,23 @@ int mysql_update(THD *thd,
We can't update table directly; We must first search after all
matching rows before updating the table!
*/
- table->file->ha_retrieve_all_cols();
if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
{
table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
+ table->mark_columns_used_by_index(used_index);
+ }
+ else
+ {
+ table->use_all_columns();
}
- /* note: can actually avoid sorting below.. */
+ /* note: We avoid sorting avoid if we sort on the used index */
if (order && (need_sort || used_key_is_modified))
{
/*
Doing an ORDER BY; Let filesort find and sort the rows we are going
to update
+ NOTE: filesort will call table->prepare_for_position()
*/
uint length;
SORT_FIELD *sortorder;
@@ -334,12 +323,11 @@ int mysql_update(THD *thd,
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->sort.found_records = filesort(thd, table, sortorder, length,
- select, limit,
- &examined_rows))
+ (table->sort.found_records= filesort(thd, table, sortorder, length,
+ select, limit, 1,
+ &examined_rows))
== HA_POS_ERROR)
{
- free_io_cache(table);
goto err;
}
/*
@@ -365,6 +353,7 @@ int mysql_update(THD *thd,
/* If quick select is used, initialize it before retrieving rows. */
if (select && select->quick && select->quick->reset())
goto err;
+ table->file->try_semi_consistent_read(1);
/*
When we get here, we have one of the following options:
@@ -376,11 +365,6 @@ int mysql_update(THD *thd,
B.2 quick select is not used, this is full index scan (with LIMIT)
Full index scan must be started with init_read_record_idx
*/
- /* If quick select is used, initialize it before retrieving rows. */
- if (select && select->quick && select->quick->reset())
- goto err;
-
- table->file->try_semi_consistent_read(1);
if (used_index == MAX_KEY || (select && select->quick))
init_read_record(&info,thd,table,select,0,1);
@@ -440,17 +424,14 @@ int mysql_update(THD *thd,
goto err;
}
if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->restore_column_maps_after_mark_index();
}
if (ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (select && select->quick && select->quick->reset())
- goto err;
+ goto err;
table->file->try_semi_consistent_read(1);
init_read_record(&info,thd,table,select,0,1);
@@ -458,7 +439,6 @@ int mysql_update(THD *thd,
thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
thd->cuted_fields=0L;
thd->proc_info="Updating";
- query_id=thd->query_id;
transactional_table= table->file->has_transactions();
thd->no_trans_update= 0;
@@ -468,12 +448,23 @@ int mysql_update(THD *thd,
MODE_STRICT_ALL_TABLES)));
will_batch= !table->file->start_bulk_update();
+ table->mark_columns_needed_for_update();
+
+ /*
+ We can use compare_record() to optimize away updates if
+ the table handler is returning all columns OR if
+ if all updated columns are read
+ */
+ can_compare_record= (!(table->file->ha_table_flags() &
+ HA_PARTIAL_COLUMN_READ) ||
+ bitmap_is_subset(table->write_set, table->read_set));
+
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (!(select && select->skip_record()))
{
if (table->file->was_semi_consistent_read())
- continue; /* repeat the read of the same row if it still exists */
+ continue; /* repeat the read of the same row if it still exists */
store_record(table,record[1]);
if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
@@ -483,7 +474,7 @@ int mysql_update(THD *thd,
found++;
- if (compare_record(table, query_id))
+ if (!can_compare_record || compare_record(table))
{
if ((res= table_list->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK)
@@ -632,7 +623,6 @@ int mysql_update(THD *thd,
table->file->end_bulk_update();
table->file->try_semi_consistent_read(0);
end_read_record(&info);
- free_io_cache(table); // If ORDER BY
delete select;
thd->proc_info= "end";
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
@@ -698,7 +688,6 @@ int mysql_update(THD *thd,
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
thd->abort_on_warning= 0;
- free_io_cache(table);
DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
err:
@@ -748,9 +737,11 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
tables.alias= table_list->alias;
thd->lex->allow_sum_func= 0;
- if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
- table_list, conds, &select_lex->leaf_tables,
- FALSE) ||
+ if (setup_tables_and_check_access(thd, &select_lex->context,
+ &select_lex->top_join_list,
+ table_list,
+ &select_lex->leaf_tables,
+ FALSE, UPDATE_ACL) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
select_lex->setup_ref_array(thd, order_num) ||
setup_order(thd, select_lex->ref_pointer_array,
@@ -841,13 +832,14 @@ reopen_tables:
call in setup_tables()).
*/
- if (setup_tables(thd, &lex->select_lex.context,
- &lex->select_lex.top_join_list,
- table_list, &lex->select_lex.where,
- &lex->select_lex.leaf_tables, FALSE))
+ if (setup_tables_and_check_access(thd, &lex->select_lex.context,
+ &lex->select_lex.top_join_list,
+ table_list,
+ &lex->select_lex.leaf_tables, FALSE,
+ UPDATE_ACL))
DBUG_RETURN(TRUE);
- if (setup_fields_with_no_wrap(thd, 0, *fields, 2, 0, 0))
+ if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(TRUE);
for (tl= table_list; tl ; tl= tl->next_local)
@@ -875,7 +867,8 @@ reopen_tables:
TABLE *table= tl->table;
/* Only set timestamp column if this is not modified */
if (table->timestamp_field &&
- table->timestamp_field->query_id == thd->query_id)
+ bitmap_is_set(table->write_set,
+ table->timestamp_field->field_index))
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/* if table will be updated then check that it is unique */
@@ -887,6 +880,7 @@ reopen_tables:
DBUG_RETURN(TRUE);
}
+ table->mark_columns_needed_for_update();
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
/*
If table will be updated we should not downgrade lock for it and
@@ -1088,7 +1082,7 @@ int multi_update::prepare(List<Item> &not_used_values,
reference tables
*/
- if (setup_fields(thd, 0, *values, 1, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(1);
/*
@@ -1207,7 +1201,9 @@ multi_update::initialize_tables(JOIN *join)
Item_field *ifield;
List<Item> temp_fields= *fields_for_table[cnt];
ORDER group;
+ TMP_TABLE_PARAM *tmp_param;
+ table->mark_columns_needed_for_update();
if (table == main_table) // First table in join
{
if (safe_update_on_fly(join->join_tab, &temp_fields))
@@ -1216,9 +1212,9 @@ multi_update::initialize_tables(JOIN *join)
continue;
}
}
+ table->prepare_for_position();
- TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
-
+ tmp_param= tmp_table_param+cnt;
/*
Create a temporary table to store all fields that are changed for this
table. The first field in the temporary table is a pointer to the
@@ -1313,7 +1309,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
!(table->triggers &&
table->triggers->has_before_update_triggers());
/* If scanning in clustered key */
- if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key < MAX_KEY)
return !check_if_key_used(table, table->s->primary_key, *fields) &&
!(table->triggers &&
@@ -1359,6 +1355,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
TABLE *table= cur_table->table;
+ uint offset= cur_table->shared;
/*
Check if we are using outer join and we didn't find the row
or if we have already updated this row in the previous call to this
@@ -1374,10 +1371,18 @@ bool multi_update::send_data(List<Item> &not_used_values)
if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
continue;
- uint offset= cur_table->shared;
- table->file->position(table->record[0]);
+ /*
+ We can use compare_record() to optimize away updates if
+ the table handler is returning all columns OR if
+ if all updated columns are read
+ */
if (table == table_to_update)
{
+ bool can_compare_record;
+ can_compare_record= (!(table->file->ha_table_flags() &
+ HA_PARTIAL_COLUMN_READ) ||
+ bitmap_is_subset(table->write_set,
+ table->read_set));
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
@@ -1387,7 +1392,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
DBUG_RETURN(1);
found++;
- if (compare_record(table, thd->query_id))
+ if (!can_compare_record || compare_record(table))
{
int error;
if ((error= cur_table->view_check_option(thd, ignore)) !=
@@ -1439,6 +1444,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
{
int error;
TABLE *tmp_table= tmp_tables[offset];
+ table->file->position(table->record[0]);
fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
/* Store pointer to row */
memcpy((char*) tmp_table->field[0]->ptr,
@@ -1504,6 +1510,7 @@ int multi_update::do_updates(bool from_send_error)
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
byte *ref_pos;
+ bool can_compare_record;
table = cur_table->table;
if (table == table_to_update)
@@ -1530,6 +1537,11 @@ int multi_update::do_updates(bool from_send_error)
if ((local_error = tmp_table->file->ha_rnd_init(1)))
goto err;
+ can_compare_record= (!(table->file->ha_table_flags() &
+ HA_PARTIAL_COLUMN_READ) ||
+ bitmap_is_subset(table->write_set,
+ table->read_set));
+
ref_pos= (byte*) tmp_table->field[0]->ptr;
for (;;)
{
@@ -1559,7 +1571,7 @@ int multi_update::do_updates(bool from_send_error)
TRG_ACTION_BEFORE, TRUE))
goto err2;
- if (compare_record(table, thd->query_id))
+ if (!can_compare_record || compare_record(table))
{
if ((local_error=table->file->ha_update_row(table->record[1],
table->record[0])))
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 8e5a776950d..d1e7ba80ecf 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1191,9 +1191,11 @@ ok:
ok2:
if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
+ DBUG_ASSERT(lex == thd->lex);
+ thd->lex= old_lex; // Needed for prepare_security
result= !table->prelocking_placeholder && table->prepare_security(thd);
- lex_end(thd->lex);
+ lex_end(lex);
end:
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -1343,8 +1345,8 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt)
view view for check with opened table
DESCRIPTION
- If it is VIEW and query have LIMIT clause then check that undertlying
- table of viey contain one of following:
+ If it is VIEW and query have LIMIT clause then check that underlying
+ table of view contain one of following:
1) primary key of underlying table
2) unique key underlying table with fields for which NULL value is
impossible
@@ -1385,19 +1387,19 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
this operation should not have influence on Field::query_id, to avoid
marking as used fields which are not used
*/
- bool save_set_query_id= thd->set_query_id;
- thd->set_query_id= 0;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
+ thd->mark_used_columns= MARK_COLUMNS_NONE;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
for (Field_translator *fld= trans; fld < end_of_trans; fld++)
{
if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item))
{
- thd->set_query_id= save_set_query_id;
+ thd->mark_used_columns= save_mark_used_columns;
return TRUE;
}
}
- thd->set_query_id= save_set_query_id;
- DBUG_PRINT("info", ("thd->set_query_id: %d", thd->set_query_id));
+ thd->mark_used_columns= save_mark_used_columns;
+ DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
}
/* Loop over all keys to see if a unique-not-null key is used */
for (;key_info != key_info_end ; key_info++)
@@ -1550,7 +1552,6 @@ mysql_rename_view(THD *thd,
File_parser *parser;
char view_path[FN_REFLEN];
bool error= TRUE;
-
DBUG_ENTER("mysql_rename_view");
strxnmov(view_path, FN_REFLEN-1, mysql_data_home, "/", view->db, "/",
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fb84d5e4459..a8c93b683b3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -204,6 +204,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CONSTRAINT
%token CONTAINS_SYM
%token CONTINUE_SYM
+%token CONTRIBUTORS_SYM
%token CONVERT_SYM
%token CONVERT_TZ_SYM
%token COUNT_SYM
@@ -568,6 +569,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token RTREE_SYM
%token SAVEPOINT_SYM
%token SCHEDULE_SYM
+%token SCHEDULER_SYM
%token SECOND_MICROSECOND_SYM
%token SECOND_SYM
%token SECURITY_SYM
@@ -1383,7 +1385,7 @@ ev_schedule_time: EVERY_SYM expr interval
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
my_error(ER_WRONG_VALUE, MYF(0), "AT",
- str2? str2->c_ptr():"NULL");
+ str2? str2->c_ptr_safe():"NULL");
YYABORT;
break;
}
@@ -1401,7 +1403,7 @@ opt_ev_status: /* empty */ { $$= 0; }
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
- lex->et->status= MYSQL_EVENT_ENABLED;
+ lex->et->status= Event_timed::ENABLED;
$$= 1;
}
| DISABLE_SYM
@@ -1409,7 +1411,7 @@ opt_ev_status: /* empty */ { $$= 0; }
LEX *lex=Lex;
if (!lex->et_compile_phase)
- lex->et->status= MYSQL_EVENT_DISABLED;
+ lex->et->status= Event_timed::DISABLED;
$$= 1;
}
;
@@ -1434,8 +1436,8 @@ ev_starts: /* empty */
char buff[20];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
- my_error(ER_WRONG_VALUE, MYF(0), "STARTS", str2? str2->c_ptr():
- NULL);
+ my_error(ER_WRONG_VALUE, MYF(0), "STARTS",
+ str2 ? str2->c_ptr_safe() : NULL);
YYABORT;
break;
}
@@ -1473,14 +1475,14 @@ ev_on_completion:
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
- lex->et->on_completion= MYSQL_EVENT_ON_COMPLETION_PRESERVE;
+ lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
- lex->et->on_completion= MYSQL_EVENT_ON_COMPLETION_DROP;
+ lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
$$= 1;
}
;
@@ -3100,11 +3102,11 @@ opt_ts_engine:
"STORAGE ENGINE");
YYABORT;
}
- lex->alter_tablespace_info->storage_engine= $4 ? $4 : &default_hton;
+ lex->alter_tablespace_info->storage_engine= $4;
};
opt_ts_wait:
- /* empty */
+ /* empty */
| ts_wait
;
@@ -3940,12 +3942,18 @@ storage_engines:
ident_or_text
{
$$ = ha_resolve_by_name(YYTHD, &$1);
- if ($$ == NULL &&
- test(YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION))
+ if ($$ == NULL)
+ if (YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
YYABORT;
}
+ else
+ {
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_UNKNOWN_STORAGE_ENGINE,
+ ER(ER_UNKNOWN_STORAGE_ENGINE), $1.str);
+ }
};
row_types:
@@ -4622,7 +4630,7 @@ alter:
lex->select_lex.db=lex->name= 0;
lex->like_name= 0;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
- lex->create_info.db_type= (handlerton*) &default_hton;
+ lex->create_info.db_type= 0;
lex->create_info.default_table_charset= NULL;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
lex->alter_info.reset();
@@ -8067,15 +8075,24 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
YYABORT;
}
- | opt_full EVENTS_SYM opt_db wild_and_where
+ | EVENTS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_EVENTS;
- lex->select_lex.db= $3;
+ lex->select_lex.db= $2;
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
YYABORT;
}
+ | SCHEDULER_SYM STATUS_SYM
+ {
+#ifndef DBUG_OFF
+ Lex->sql_command= SQLCOM_SHOW_SCHEDULER_STATUS;
+#else
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+#endif
+ }
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
@@ -8184,6 +8201,11 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_AUTHORS;
}
+ | CONTRIBUTORS_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_CONTRIBUTORS;
+ }
| PRIVILEGES
{
LEX *lex=Lex;
@@ -9512,6 +9534,7 @@ keyword_sp:
| ROW_SYM {}
| RTREE_SYM {}
| SCHEDULE_SYM {}
+ | SCHEDULER_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}
diff --git a/sql/structs.h b/sql/structs.h
index 72237887514..78f00f72df1 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -20,22 +20,6 @@
struct st_table;
class Field;
-typedef struct st_lex_string
-{
- char *str;
- uint length;
-} LEX_STRING;
-
-typedef struct st_lex_string_with_init :public st_lex_string
-{
- st_lex_string_with_init(const char *str_arg, uint length_arg)
- {
- str= (char*) str_arg;
- length= length_arg;
- }
-} LEX_STRING_WITH_INIT;
-
-
typedef struct st_date_time_format {
uchar positions[8];
char time_separator; /* Separator between hour and minute */
diff --git a/sql/table.cc b/sql/table.cc
index 52f41f03d0d..45db45b1ffd 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -18,7 +18,7 @@
/* Some general useful functions */
#include "mysql_priv.h"
-#include <errno.h>
+#include "sql_trigger.h"
#include <m_ctype.h>
#include "md5.h"
@@ -93,21 +93,16 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
{
MEM_ROOT mem_root;
TABLE_SHARE *share;
- char path[FN_REFLEN], normalized_path[FN_REFLEN];
- uint path_length, normalized_length;
+ char path[FN_REFLEN];
+ uint path_length;
path_length= build_table_filename(path, sizeof(path) - 1,
table_list->db,
table_list->table_name, "");
- normalized_length= build_table_filename(normalized_path,
- sizeof(normalized_path) - 1,
- table_list->db,
- table_list->table_name, "");
-
init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
if ((share= (TABLE_SHARE*) alloc_root(&mem_root,
sizeof(*share) + key_length +
- path_length + normalized_length +2)))
+ path_length +1)))
{
bzero((char*) share, sizeof(*share));
share->table_cache_key.str= (char*) (share+1);
@@ -123,9 +118,8 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
share->path.str= share->table_cache_key.str+ key_length;
share->path.length= path_length;
strmov(share->path.str, path);
- share->normalized_path.str= share->path.str+ path_length+1;
- share->normalized_path.length= normalized_length;
- strmov(share->normalized_path.str, normalized_path);
+ share->normalized_path.str= share->path.str;
+ share->normalized_path.length= path_length;
share->version= refresh_version;
share->flush_version= flush_version;
@@ -434,6 +428,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
Field **field_ptr, *reg_field;
const char **interval_array;
enum legacy_db_type legacy_db_type;
+ my_bitmap_map *bitmaps;
DBUG_ENTER("open_binary_frm");
new_field_pack_flag= head[27];
@@ -984,7 +979,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
goto err; /* purecov: inspected */
}
- reg_field->fieldnr= i+1; //Set field number
reg_field->field_index= i;
reg_field->comment=comment;
if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
@@ -1019,7 +1013,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
uint primary_key=(uint) (find_type((char*) primary_key_name,
&share->keynames, 3) - 1);
- uint ha_option= handler_file->table_flags();
+ uint ha_option= handler_file->ha_table_flags();
keyinfo= share->key_info;
key_part= keyinfo->key_part;
@@ -1108,6 +1102,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
share->keys_for_keyread.set_bit(key);
field->part_of_key.set_bit(key);
+ field->part_of_key_not_clustered.set_bit(key);
}
if (handler_file->index_flags(key, i, 1) & HA_READ_ORDER)
field->part_of_sortkey.set_bit(key);
@@ -1265,6 +1260,14 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->last_null_bit_pos= null_bit_pos;
share->db_low_byte_first= handler_file->low_byte_first();
+ share->column_bitmap_size= bitmap_buffer_size(share->fields);
+
+ if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root,
+ share->column_bitmap_size)))
+ goto err;
+ bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);
+ bitmap_set_all(&share->all_set);
+
delete handler_file;
#ifndef DBUG_OFF
if (use_hash)
@@ -1316,18 +1319,15 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
TABLE *outparam, bool is_create_table)
{
int error;
- uint records, i;
+ uint records, i, bitmap_size;
bool error_reported= FALSE;
- byte *record;
+ byte *record, *bitmaps;
Field **field_ptr;
- MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
share->table_name.str, outparam));
error= 1;
- root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
- old_root= *root_ptr;
bzero((char*) outparam, sizeof(*outparam));
outparam->in_use= thd;
outparam->s= share;
@@ -1335,7 +1335,6 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
outparam->write_row_record= NULL;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
- *root_ptr= &outparam->mem_root;
if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
goto err;
@@ -1467,25 +1466,42 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->partition_info_len)
{
- if (mysql_unpack_partition(thd, share->partition_info,
- share->partition_info_len,
- (uchar*)share->part_state,
- share->part_state_len,
- outparam, is_create_table,
- share->default_part_db_type))
- goto err;
- /*
- Fix the partition functions and ensure they are not constant
- functions
- */
+ MEM_ROOT **root_ptr, *old_root;
+ bool tmp;
+ root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
+ old_root= *root_ptr;
+ *root_ptr= &outparam->mem_root;
+
+ tmp= mysql_unpack_partition(thd, share->partition_info,
+ share->partition_info_len,
+ (uchar*)share->part_state,
+ share->part_state_len,
+ outparam, is_create_table,
+ share->default_part_db_type);
outparam->part_info->is_auto_partitioned= share->auto_partitioned;
- DBUG_PRINT("info", ("autopartitioned = %u", share->auto_partitioned));
- if (fix_partition_func(thd, share->normalized_path.str, outparam,
- is_create_table))
+ DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
+ if (!tmp)
+ tmp= fix_partition_func(thd, share->normalized_path.str, outparam,
+ is_create_table);
+ *root_ptr= old_root;
+ if (tmp)
goto err;
}
#endif
+ /* Allocate bitmaps */
+
+ bitmap_size= share->column_bitmap_size;
+ if (!(bitmaps= (byte*) alloc_root(&outparam->mem_root, bitmap_size*3)))
+ goto err;
+ bitmap_init(&outparam->def_read_set,
+ (my_bitmap_map*) bitmaps, share->fields, FALSE);
+ bitmap_init(&outparam->def_write_set,
+ (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE);
+ bitmap_init(&outparam->tmp_set,
+ (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE);
+ outparam->default_column_bitmaps();
+
/* The table struct is now initialized; Open the table */
error= 2;
if (db_stat)
@@ -1527,13 +1543,15 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
}
}
- *root_ptr= old_root;
+#if defined(HAVE_purify) && !defined(DBUG_OFF)
+ bzero((char*) bitmaps, bitmap_size*3);
+#endif
+
thd->status_var.opened_tables++;
DBUG_RETURN (0);
err:
- *root_ptr= old_root;
if (! error_reported)
open_table_error(share, error, my_errno, 0);
delete outparam->file;
@@ -1564,6 +1582,7 @@ int closefrm(register TABLE *table, bool free_share)
uint idx;
KEY *key_info;
DBUG_ENTER("closefrm");
+ DBUG_PRINT("enter", ("table: 0x%lx", (long) table));
if (table->db_stat)
error=table->file->close();
@@ -2347,7 +2366,7 @@ table_check_intact(TABLE *table, uint table_f_count,
DBUG_PRINT("info",("last_create_time=%d", *last_create_time));
if ((fields_diff_count= (table->s->fields != table_f_count)) ||
- (*last_create_time != table->file->create_time))
+ (*last_create_time != table->file->stats.create_time))
{
DBUG_PRINT("info", ("I am suspecting, checking table"));
if (fields_diff_count)
@@ -2355,33 +2374,46 @@ table_check_intact(TABLE *table, uint table_f_count,
// previous MySQL version
error= TRUE;
if (MYSQL_VERSION_ID > table->s->mysql_version)
+ {
my_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, MYF(0), table->alias,
table_f_count, table->s->fields, table->s->mysql_version,
MYSQL_VERSION_ID);
+ sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
+ table->alias, table_f_count, table->s->fields,
+ table->s->mysql_version, MYSQL_VERSION_ID);
+ DBUG_RETURN(error);
+
+ }
else if (MYSQL_VERSION_ID == table->s->mysql_version)
+ {
my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED,MYF(0), table->alias,
table_f_count, table->s->fields);
+ sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias,
+ table_f_count, table->s->fields);
+ }
else
+ {
/*
moving from newer mysql to older one -> let's say not an error but
- will check the definition afterwards. If a column was added at the end
- then we don't care much since it's not in the middle.
+ will check the definition afterwards. If a column was added at the
+ end then we don't care much since it's not in the middle.
*/
error= FALSE;
+ }
}
//definitely something has changed
char buffer[255];
- for (i=0 ;i < table_f_count; ++i, ++table_def)
+ for (i=0 ; i < table_f_count; i++, table_def++)
{
- Field *field= table->field[i];
String sql_type(buffer, sizeof(buffer), system_charset_info);
sql_type.length(0);
/*
name changes are not fatal, we use sequence numbers => no prob for us
but this can show tampered table or broken table.
*/
- if (!fields_diff_count || i < table->s->fields)
+ if (i < table->s->fields)
{
+ Field *field= table->field[i];
if (strncmp(field->field_name, table_def->name.str,
table_def->name.length))
{
@@ -2401,9 +2433,7 @@ table_check_intact(TABLE *table, uint table_f_count,
table running on a old server will be valid.
*/
field->sql_type(sql_type);
- if (sql_type.length() < table_def->type.length - 1 ||
- strncmp(sql_type.ptr(),
- table_def->type.str,
+ if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
table_def->type.length - 1))
{
sql_print_error("(%s) Expected field %s at position %d to have type "
@@ -2431,20 +2461,20 @@ table_check_intact(TABLE *table, uint table_f_count,
else
{
sql_print_error("(%s) Expected field %s at position %d to have type %s "
- " but no field found.", table_def->name.str,
+ " but no field found.", table->alias,
table_def->name.str, i, table_def->type.str);
error= TRUE;
}
}
if (!error)
- *last_create_time= table->file->create_time;
+ *last_create_time= table->file->stats.create_time;
else if (!fields_diff_count && error_num)
my_error(error_num,MYF(0), table->alias, table_f_count, table->s->fields);
}
else
{
DBUG_PRINT("info", ("Table seems ok without thorough checking."));
- *last_create_time= table->file->create_time;
+ *last_create_time= table->file->stats.create_time;
}
DBUG_RETURN(error);
@@ -2823,7 +2853,8 @@ void st_table_list::hide_view_error(THD *thd)
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR)
+ thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
+ thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR)
{
TABLE_LIST *top= top_table();
thd->clear_error();
@@ -2883,7 +2914,7 @@ void st_table_list::cleanup_items()
for (Field_translator *transl= field_translation;
transl < field_translation_end;
transl++)
- transl->item->walk(&Item::cleanup_processor, 0);
+ transl->item->walk(&Item::cleanup_processor, 0, 0);
}
@@ -3183,8 +3214,18 @@ bool st_table_list::prepare_view_securety_context(THD *thd)
definer.host.str,
thd->db))
{
- my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
- DBUG_RETURN(TRUE);
+ if (thd->lex->sql_command == SQLCOM_SHOW_CREATE)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ definer.user.str, definer.host.str);
+ }
+ else
+ {
+ my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
+ DBUG_RETURN(TRUE);
+ }
}
}
DBUG_RETURN(FALSE);
@@ -3433,7 +3474,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
field= *field_ref;
}
thd->lex->current_select->no_wrap_view_item= save_wrapper;
- if (thd->lex->current_select->no_wrap_view_item)
+ if (save_wrapper)
{
DBUG_RETURN(field);
}
@@ -3727,6 +3768,276 @@ Field_iterator_table_ref::get_natural_column_ref()
return nj_col;
}
+/*****************************************************************************
+ Functions to handle column usage bitmaps (read_set, write_set etc...)
+*****************************************************************************/
+
+/* Reset all columns bitmaps */
+
+void st_table::clear_column_bitmaps()
+{
+ /*
+ Reset column read/write usage. It's identical to:
+ bitmap_clear_all(&table->def_read_set);
+ bitmap_clear_all(&table->def_write_set);
+ */
+ bzero((char*) def_read_set.bitmap, s->column_bitmap_size*2);
+ column_bitmaps_set(&def_read_set, &def_write_set);
+}
+
+
+/*
+ Tell handler we are going to call position() and rnd_pos() later.
+
+ NOTES:
+ This is needed for handlers that uses the primary key to find the
+ row. In this case we have to extend the read bitmap with the primary
+ key fields.
+*/
+
+void st_table::prepare_for_position()
+{
+ DBUG_ENTER("st_table::prepare_for_position");
+
+ if ((file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
+ s->primary_key < MAX_KEY)
+ {
+ mark_columns_used_by_index_no_reset(s->primary_key, read_set);
+ /* signal change */
+ file->column_bitmaps_signal();
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Mark that only fields from one key is used
+
+ NOTE:
+ This changes the bitmap to use the tmp bitmap
+ After this, you can't access any other columns in the table until
+ bitmaps are reset, for example with st_table::clear_column_bitmaps()
+ or st_table::restore_column_maps_after_mark_index()
+*/
+
+void st_table::mark_columns_used_by_index(uint index)
+{
+ MY_BITMAP *bitmap= &tmp_set;
+ DBUG_ENTER("st_table::mark_columns_used_by_index");
+
+ (void) file->extra(HA_EXTRA_KEYREAD);
+ bitmap_clear_all(bitmap);
+ mark_columns_used_by_index_no_reset(index, bitmap);
+ column_bitmaps_set(bitmap, bitmap);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Restore to use normal column maps after key read
+
+ NOTES
+ This reverse the change done by mark_columns_used_by_index
+
+ WARNING
+ For this to work, one must have the normal table maps in place
+ when calling mark_columns_used_by_index
+*/
+
+void st_table::restore_column_maps_after_mark_index()
+{
+ DBUG_ENTER("st_table::restore_column_maps_after_mark_index");
+
+ key_read= 0;
+ (void) file->extra(HA_EXTRA_NO_KEYREAD);
+ default_column_bitmaps();
+ file->column_bitmaps_signal();
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ mark columns used by key, but don't reset other fields
+*/
+
+void st_table::mark_columns_used_by_index_no_reset(uint index,
+ MY_BITMAP *bitmap)
+{
+ KEY_PART_INFO *key_part= key_info[index].key_part;
+ KEY_PART_INFO *key_part_end= (key_part +
+ key_info[index].key_parts);
+ for (;key_part != key_part_end; key_part++)
+ bitmap_set_bit(bitmap, key_part->fieldnr-1);
+}
+
+
+/*
+ Mark auto-increment fields as used fields in both read and write maps
+
+ NOTES
+ This is needed in insert & update as the auto-increment field is
+ always set and sometimes read.
+*/
+
+void st_table::mark_auto_increment_column()
+{
+ DBUG_ASSERT(found_next_number_field);
+ /*
+ We must set bit in read set as update_auto_increment() is using the
+ store() to check overflow of auto_increment values
+ */
+ bitmap_set_bit(read_set, found_next_number_field->field_index);
+ bitmap_set_bit(write_set, found_next_number_field->field_index);
+ if (s->next_number_key_offset)
+ mark_columns_used_by_index_no_reset(s->next_number_index, read_set);
+ file->column_bitmaps_signal();
+}
+
+
+/*
+ Mark columns needed for doing an delete of a row
+
+ DESCRIPTON
+ Some table engines don't have a cursor on the retrieve rows
+ so they need either to use the primary key or all columns to
+ be able to delete a row.
+
+ If the engine needs this, the function works as follows:
+ - If primary key exits, mark the primary key columns to be read.
+ - If not, mark all columns to be read
+
+ If the engine has HA_REQUIRES_KEY_COLUMNS_FOR_DELETE, we will
+ mark all key columns as 'to-be-read'. This allows the engine to
+ loop over the given record to find all keys and doesn't have to
+ retrieve the row again.
+*/
+
+void st_table::mark_columns_needed_for_delete()
+{
+ if (triggers)
+ {
+ if (triggers->bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
+ triggers->bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER])
+ {
+ /* TODO: optimize to only add columns used by trigger */
+ use_all_columns();
+ return;
+ }
+ }
+
+ if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE)
+ {
+ Field **reg_field;
+ for (reg_field= field ; *reg_field ; reg_field++)
+ {
+ if ((*reg_field)->flags & PART_KEY_FLAG)
+ bitmap_set_bit(read_set, (*reg_field)->field_index);
+ }
+ file->column_bitmaps_signal();
+ }
+ if (file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_DELETE)
+ {
+ /*
+ If the handler has no cursor capabilites, we have to read either
+ the primary key, the hidden primary key or all columns to be
+ able to do an delete
+ */
+ if (s->primary_key == MAX_KEY)
+ file->use_hidden_primary_key();
+ else
+ {
+ mark_columns_used_by_index_no_reset(s->primary_key, read_set);
+ file->column_bitmaps_signal();
+ }
+ }
+}
+
+
+/*
+ Mark columns needed for doing an update of a row
+
+ DESCRIPTON
+ Some engines needs to have all columns in an update (to be able to
+ build a complete row). If this is the case, we mark all not
+ updated columns to be read.
+
+ If this is no the case, we do like in the delete case and mark
+ if neeed, either the primary key column or all columns to be read.
+ (see mark_columns_needed_for_delete() for details)
+
+ If the engine has HA_REQUIRES_KEY_COLUMNS_FOR_DELETE, we will
+ mark all USED key columns as 'to-be-read'. This allows the engine to
+ loop over the given record to find all changed keys and doesn't have to
+ retrieve the row again.
+*/
+
+void st_table::mark_columns_needed_for_update()
+{
+ DBUG_ENTER("mark_columns_needed_for_update");
+ if (triggers)
+ {
+ if (triggers->bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE] ||
+ triggers->bodies[TRG_EVENT_UPDATE][TRG_ACTION_AFTER])
+ {
+ /* TODO: optimize to only add columns used by trigger */
+ use_all_columns();
+ DBUG_VOID_RETURN;
+ }
+ }
+ if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE)
+ {
+ /* Mark all used key columns for read */
+ Field **reg_field;
+ for (reg_field= field ; *reg_field ; reg_field++)
+ {
+ /* Merge keys is all keys that had a column refered to in the query */
+ if (merge_keys.is_overlapping((*reg_field)->part_of_key))
+ bitmap_set_bit(read_set, (*reg_field)->field_index);
+ }
+ file->column_bitmaps_signal();
+ }
+ if (file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_DELETE)
+ {
+ /*
+ If the handler has no cursor capabilites, we have to read either
+ the primary key, the hidden primary key or all columns to be
+ able to do an update
+ */
+ if (s->primary_key == MAX_KEY)
+ file->use_hidden_primary_key();
+ else
+ {
+ mark_columns_used_by_index_no_reset(s->primary_key, read_set);
+ file->column_bitmaps_signal();
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Mark columns the handler needs for doing an insert
+
+ For now, this is used to mark fields used by the trigger
+ as changed.
+*/
+
+void st_table::mark_columns_needed_for_insert()
+{
+ if (triggers)
+ {
+ if (triggers->bodies[TRG_EVENT_INSERT][TRG_ACTION_BEFORE] ||
+ triggers->bodies[TRG_EVENT_INSERT][TRG_ACTION_AFTER])
+ {
+ /* TODO: optimize to only add columns used by trigger */
+ use_all_columns();
+ return;
+ }
+ }
+ if (found_next_number_field)
+ mark_auto_increment_column();
+}
+
/*****************************************************************************
** Instansiate templates
diff --git a/sql/table.h b/sql/table.h
index ffecc60b19c..71a199d946e 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -137,6 +137,7 @@ typedef struct st_table_share
char *comment; /* Comment about table */
CHARSET_INFO *table_charset; /* Default charset of string fields */
+ MY_BITMAP all_set;
/* A pair "database_name\0table_name\0", widely used as simply a db name */
LEX_STRING table_cache_key;
LEX_STRING db; /* Pointer to db */
@@ -181,6 +182,7 @@ typedef struct st_table_share
uint next_number_index;
uint next_number_key_offset;
uint error, open_errno, errarg; /* error from open_table_def() */
+ uint column_bitmap_size;
uchar frm_version;
bool null_field_first;
bool system; /* Set if system table (one record) */
@@ -244,7 +246,7 @@ struct st_table {
byte *write_row_record; /* Used as optimisation in
THD::write_row */
byte *insert_values; /* used by INSERT ... UPDATE */
- key_map quick_keys, used_keys, keys_in_use_for_query;
+ key_map quick_keys, used_keys, keys_in_use_for_query, merge_keys;
KEY *key_info; /* data of keys in database */
Field *next_number_field; /* Set if next_number is activated */
@@ -257,8 +259,9 @@ struct st_table {
ORDER *group;
const char *alias; /* alias or table name */
uchar *null_flags;
- MY_BITMAP *read_set;
- MY_BITMAP *write_set;
+ my_bitmap_map *bitmap_init_value;
+ MY_BITMAP def_read_set, def_write_set, tmp_set; /* containers */
+ MY_BITMAP *read_set, *write_set; /* Active column sets */
query_id_t query_id;
ha_rows quick_rows[MAX_KEY];
@@ -330,6 +333,39 @@ struct st_table {
bool fill_item_list(List<Item> *item_list) const;
void reset_item_list(List<Item> *item_list) const;
+ void clear_column_bitmaps(void);
+ void prepare_for_position(void);
+ void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map);
+ void mark_columns_used_by_index(uint index);
+ void restore_column_maps_after_mark_index();
+ void mark_auto_increment_column(void);
+ void mark_columns_needed_for_update(void);
+ void mark_columns_needed_for_delete(void);
+ void mark_columns_needed_for_insert(void);
+ inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
+ MY_BITMAP *write_set_arg)
+ {
+ read_set= read_set_arg;
+ write_set= write_set_arg;
+ if (file)
+ file->column_bitmaps_signal();
+ }
+ inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg,
+ MY_BITMAP *write_set_arg)
+ {
+ read_set= read_set_arg;
+ write_set= write_set_arg;
+ }
+ inline void use_all_columns()
+ {
+ column_bitmaps_set(&s->all_set, &s->all_set);
+ }
+ inline void default_column_bitmaps()
+ {
+ read_set= &def_read_set;
+ write_set= &def_write_set;
+ }
+
};
@@ -901,3 +937,38 @@ my_bool
table_check_intact(TABLE *table, uint table_f_count,
TABLE_FIELD_W_TYPE *table_def, time_t *last_create_time,
int error_num);
+
+static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
+ MY_BITMAP *bitmap)
+{
+ my_bitmap_map *old= bitmap->bitmap;
+ bitmap->bitmap= table->s->all_set.bitmap;
+ return old;
+}
+
+
+static inline void tmp_restore_column_map(MY_BITMAP *bitmap,
+ my_bitmap_map *old)
+{
+ bitmap->bitmap= old;
+}
+
+/* The following is only needed for debugging */
+
+static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table,
+ MY_BITMAP *bitmap)
+{
+#ifndef DBUG_OFF
+ return tmp_use_all_columns(table, bitmap);
+#else
+ return 0;
+#endif
+}
+
+static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap,
+ my_bitmap_map *old)
+{
+#ifndef DBUG_OFF
+ tmp_restore_column_map(bitmap, old);
+#endif
+}
diff --git a/sql/time.cc b/sql/time.cc
index 3c654de23bb..be1e4f10825 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -692,6 +692,7 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
char buff[128];
String str(buff,(uint32) sizeof(buff), system_charset_info);
str.copy(str_val, str_length, system_charset_info);
+ str[str_length]= 0; // Ensure we have end 0 for snprintf
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 228a8cd9b92..77d7efdcf7c 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1661,6 +1661,8 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
for MyISAM.
*/
(void)table->file->ha_index_init(0, 1);
+ table->use_all_columns();
+
tz_leapcnt= 0;
res= table->file->index_first(table->record[0]);
@@ -1804,10 +1806,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
#ifdef ABBR_ARE_USED
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
#endif
-
DBUG_ENTER("tz_load_from_open_tables");
-
/* Prepare tz_info for loading also let us make copy of time zone name */
if (!(alloc_buff= alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) +
tz_name->length() + 1)))
@@ -1830,6 +1830,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
*/
table= tz_tables->table;
tz_tables= tz_tables->next_local;
+ table->use_all_columns();
table->field[0]->store(tz_name->ptr(), tz_name->length(),
&my_charset_latin1);
/*
@@ -1862,6 +1863,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
using the only index in this table).
*/
table= tz_tables->table;
+ table->use_all_columns();
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
@@ -1889,6 +1891,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Right - using special index.
*/
table= tz_tables->table;
+ table->use_all_columns();
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
@@ -1962,6 +1965,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
in ascending order by index scan also satisfies us.
*/
table= tz_tables->table;
+ table->use_all_columns();
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
@@ -2280,14 +2284,15 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
RETURN VALUE
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
specification or other error.
-
*/
+
Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
{
Time_zone *tz;
DBUG_ENTER("my_tz_find_with_opening_tables");
DBUG_ASSERT(thd);
DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
+
if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
{
/*
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index e39ee976eb1..e6c9c5dccd7 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -139,59 +139,17 @@ static HASH archive_open_tables;
#define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
/* Static declarations for handerton */
-static handler *archive_create_handler(TABLE_SHARE *table);
+static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
/*
Number of rows that will force a bulk insert.
*/
#define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2
+handlerton archive_hton;
-static const char archive_hton_name[]= "ARCHIVE";
-static const char archive_hton_comment[]= "Archive storage engine";
-
-/* dummy handlerton - only to have something to return from archive_db_init */
-handlerton archive_hton = {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- archive_hton_name,
- SHOW_OPTION_YES,
- archive_hton_comment,
- DB_TYPE_ARCHIVE_DB,
- archive_db_init,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* releas savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- archive_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- archive_db_end, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter interface */
- NULL, /* fill_files_table */
- HTON_NO_FLAGS,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-
-};
-
-static handler *archive_create_handler(TABLE_SHARE *table)
+static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_archive(table);
+ return new (mem_root) ha_archive(table);
}
/*
@@ -217,11 +175,18 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length,
TRUE Error
*/
-bool archive_db_init()
+int archive_db_init()
{
DBUG_ENTER("archive_db_init");
if (archive_inited)
DBUG_RETURN(FALSE);
+
+ archive_hton.state=SHOW_OPTION_YES;
+ archive_hton.db_type=DB_TYPE_ARCHIVE_DB;
+ archive_hton.create=archive_create_handler;
+ archive_hton.panic=archive_db_end;
+ archive_hton.flags=HTON_NO_FLAGS;
+
if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
goto error;
if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
@@ -697,18 +662,10 @@ int ha_archive::create(const char *name, TABLE *table_arg,
int error;
DBUG_ENTER("ha_archive::create");
- auto_increment_value= (create_info->auto_increment_value ?
- create_info->auto_increment_value -1 :
+ stats.auto_increment_value= (create_info->auto_increment_value ?
+ create_info->auto_increment_value -1 :
(ulonglong) 0);
- if ((create_file= my_create(fn_format(name_buff,name,"",ARM,
- MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
- O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
- {
- error= my_errno;
- goto error;
- }
-
for (uint key= 0; key < table_arg->s->keys; key++)
{
KEY *pos= table_arg->key_info+key;
@@ -722,12 +679,21 @@ int ha_archive::create(const char *name, TABLE *table_arg,
if (!(field->flags & AUTO_INCREMENT_FLAG))
{
error= -1;
+ DBUG_PRINT("info", ("Index error in creating archive table"));
goto error;
}
}
}
- write_meta_file(create_file, 0, auto_increment_value, 0,
+ if ((create_file= my_create(fn_format(name_buff,name,"",ARM,
+ MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ {
+ error= my_errno;
+ goto error;
+ }
+
+ write_meta_file(create_file, 0, stats.auto_increment_value, 0,
(char *)create_info->data_file_name,
FALSE);
my_close(create_file,MYF(0));
@@ -923,7 +889,7 @@ int ha_archive::write_row(byte *buf)
else
{
if (temp_auto > share->auto_increment_value)
- auto_increment_value= share->auto_increment_value= temp_auto;
+ stats.auto_increment_value= share->auto_increment_value= temp_auto;
}
}
@@ -946,9 +912,13 @@ error:
}
-ulonglong ha_archive::get_auto_increment()
+void ha_archive::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
{
- return share->auto_increment_value + 1;
+ *nb_reserved_values= 1;
+ *first_value= share->auto_increment_value + 1;
}
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
@@ -1058,7 +1028,7 @@ int ha_archive::rnd_init(bool scan)
{
scan_rows= share->rows_recorded;
DBUG_PRINT("info", ("archive will retrieve %llu rows", scan_rows));
- records= 0;
+ stats.records= 0;
/*
If dirty, we lock, and then reset/flush the data.
@@ -1095,6 +1065,7 @@ int ha_archive::get_row(azio_stream *file_to_read, byte *buf)
uint *ptr, *end;
char *last;
size_t total_blob_length= 0;
+ MY_BITMAP *read_set= table->read_set;
DBUG_ENTER("ha_archive::get_row");
read= azread(file_to_read, buf, table->s->reclength);
@@ -1120,8 +1091,9 @@ int ha_archive::get_row(azio_stream *file_to_read, byte *buf)
ptr != end ;
ptr++)
{
- if (ha_get_bit_in_read_set(((Field_blob*) table->field[*ptr])->fieldnr))
- total_blob_length += ((Field_blob*) table->field[*ptr])->get_length();
+ if (bitmap_is_set(read_set,
+ (((Field_blob*) table->field[*ptr])->field_index)))
+ total_blob_length += ((Field_blob*) table->field[*ptr])->get_length();
}
/* Adjust our row buffer if we need be */
@@ -1136,7 +1108,8 @@ int ha_archive::get_row(azio_stream *file_to_read, byte *buf)
size_t size= ((Field_blob*) table->field[*ptr])->get_length();
if (size)
{
- if (ha_get_bit_in_read_set(((Field_blob*) table->field[*ptr])->fieldnr))
+ if (bitmap_is_set(read_set,
+ ((Field_blob*) table->field[*ptr])->field_index))
{
read= azread(file_to_read, last, size);
if ((size_t) read != size)
@@ -1177,7 +1150,7 @@ int ha_archive::rnd_next(byte *buf)
if (rc != HA_ERR_END_OF_FILE)
- records++;
+ stats.records++;
DBUG_RETURN(rc);
}
@@ -1239,7 +1212,7 @@ int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt)
int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("ha_archive::optimize");
- int rc;
+ int rc= 0;
azio_stream writer;
char writer_filename[FN_REFLEN];
@@ -1298,7 +1271,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
if (!rc)
{
share->rows_recorded= 0;
- auto_increment_value= share->auto_increment_value= 0;
+ stats.auto_increment_value= share->auto_increment_value= 0;
while (!(rc= get_row(&archive, buf)))
{
real_write_row(buf, &writer);
@@ -1308,7 +1281,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
ulonglong auto_value=
(ulonglong) field->val_int((char*)(buf + field->offset()));
if (share->auto_increment_value < auto_value)
- auto_increment_value= share->auto_increment_value=
+ stats.auto_increment_value= share->auto_increment_value=
auto_value;
}
share->rows_recorded++;
@@ -1342,31 +1315,31 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
azclose(&writer);
share->dirty= FALSE;
share->forced_flushes= 0;
+
+ // now we close both our writer and our reader for the rename
azclose(&(share->archive_write));
- DBUG_PRINT("info", ("Reopening archive data file"));
- if (!(azopen(&(share->archive_write), share->data_file_name,
- O_WRONLY|O_APPEND|O_BINARY)))
- {
- DBUG_PRINT("info", ("Could not open archive write file"));
- rc= HA_ERR_CRASHED_ON_USAGE;
- goto error;
- }
+ azclose(&archive);
- my_rename(writer_filename,share->data_file_name,MYF(0));
+ // make the file we just wrote be our data file
+ rc = my_rename(writer_filename,share->data_file_name,MYF(0));
/*
- Now we need to reopen our read descriptor since it has changed.
+ now open the shared writer back up
+ we don't check rc here because we want to open the file back up even
+ if the optimize failed but we will return rc below so that we will
+ know it failed.
+ We also need to reopen our read descriptor since it has changed.
*/
- azclose(&archive);
- if (!(azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY)))
+ DBUG_PRINT("info", ("Reopening archive data file"));
+ if (!azopen(&(share->archive_write), share->data_file_name,
+ O_WRONLY|O_APPEND|O_BINARY) ||
+ !azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY))
{
+ DBUG_PRINT("info", ("Could not open archive write file"));
rc= HA_ERR_CRASHED_ON_USAGE;
- goto error;
}
-
- DBUG_RETURN(0);
-
+ DBUG_RETURN(rc);
error:
azclose(&writer);
@@ -1423,7 +1396,7 @@ void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
ha_archive::info(HA_STATUS_AUTO | HA_STATUS_CONST);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
{
- create_info->auto_increment_value= auto_increment_value;
+ create_info->auto_increment_value= stats.auto_increment_value;
}
if (*share->real_path)
create_info->data_file_name= share->real_path;
@@ -1440,8 +1413,8 @@ void ha_archive::info(uint flag)
This should be an accurate number now, though bulk and delayed inserts can
cause the number to be inaccurate.
*/
- records= share->rows_recorded;
- deleted= 0;
+ stats.records= share->rows_recorded;
+ stats.deleted= 0;
/* Costs quite a bit more to get all information */
if (flag & HA_STATUS_TIME)
{
@@ -1449,17 +1422,17 @@ void ha_archive::info(uint flag)
VOID(my_stat(share->data_file_name, &file_stat, MYF(MY_WME)));
- mean_rec_length= table->s->reclength + buffer.alloced_length();
- data_file_length= file_stat.st_size;
- create_time= file_stat.st_ctime;
- update_time= file_stat.st_mtime;
- max_data_file_length= share->rows_recorded * mean_rec_length;
+ stats.mean_rec_length= table->s->reclength + buffer.alloced_length();
+ stats.data_file_length= file_stat.st_size;
+ stats.create_time= file_stat.st_ctime;
+ stats.update_time= file_stat.st_mtime;
+ stats.max_data_file_length= share->rows_recorded * stats.mean_rec_length;
}
- delete_length= 0;
- index_file_length=0;
+ stats.delete_length= 0;
+ stats.index_file_length=0;
if (flag & HA_STATUS_AUTO)
- auto_increment_value= share->auto_increment_value;
+ stats.auto_increment_value= share->auto_increment_value;
DBUG_VOID_RETURN;
}
@@ -1575,16 +1548,20 @@ bool ha_archive::check_and_repair(THD *thd)
DBUG_RETURN(repair(thd, &check_opt));
}
+struct st_mysql_storage_engine archive_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &archive_hton };
mysql_declare_plugin(archive)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &archive_hton,
- archive_hton_name,
+ &archive_storage_engine,
+ "ARCHIVE",
"Brian Aker, MySQL AB",
- archive_hton_comment,
- NULL, /* Plugin Init */
+ "Archive storage engine",
+ archive_db_init, /* Plugin Init */
archive_db_done, /* Plugin Deinit */
0x0100 /* 1.0 */,
+ 0
}
mysql_declare_plugin_end;
+
diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h
index 4663531b674..0485b7e9f9c 100644
--- a/storage/archive/ha_archive.h
+++ b/storage/archive/ha_archive.h
@@ -74,16 +74,19 @@ public:
const char *table_type() const { return "ARCHIVE"; }
const char *index_type(uint inx) { return "NONE"; }
const char **bas_ext() const;
- ulong table_flags() const
+ ulonglong table_flags() const
{
- return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_CAN_BIT_FIELD |
+ return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD |
HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY);
}
ulong index_flags(uint idx, uint part, bool all_parts) const
{
return HA_ONLY_WHOLE_INDEX;
}
- ulonglong get_auto_increment();
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
uint max_supported_keys() const { return 1; }
uint max_supported_key_length() const { return sizeof(ulonglong); }
uint max_supported_key_part_length() const { return sizeof(ulonglong); }
@@ -136,6 +139,6 @@ public:
bool check_and_repair(THD *thd);
};
-bool archive_db_init(void);
+int archive_db_init(void);
int archive_db_end(ha_panic_function type);
diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc
index 098e44f39ee..1a2bb264ef9 100644
--- a/storage/blackhole/ha_blackhole.cc
+++ b/storage/blackhole/ha_blackhole.cc
@@ -22,61 +22,13 @@
#include "mysql_priv.h"
#include "ha_blackhole.h"
-#include <mysql/plugin.h>
-
/* Static declarations for handlerton */
-static handler *blackhole_create_handler(TABLE_SHARE *table);
-
-
-static const char blackhole_hton_name[]= "BLACKHOLE";
-static const char blackhole_hton_comment[]=
- "/dev/null storage engine (anything you write to it disappears)";
-
-/* Blackhole storage engine handlerton */
-
-handlerton blackhole_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- blackhole_hton_name,
- SHOW_OPTION_YES,
- blackhole_hton_comment,
- DB_TYPE_BLACKHOLE_DB,
- NULL,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- blackhole_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- NULL, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill FILES table */
- HTON_CAN_RECREATE | HTON_ALTER_CANNOT_CREATE,
- NULL, /* binlog_func */
- NULL, /* binlog_log_query */
- NULL /* release_temporary_latches */
-};
-
-
-static handler *blackhole_create_handler(TABLE_SHARE *table)
+handlerton blackhole_hton;
+static handler *blackhole_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
{
- return new ha_blackhole(table);
+ return new (mem_root) ha_blackhole(table);
}
@@ -171,16 +123,9 @@ void ha_blackhole::info(uint flag)
{
DBUG_ENTER("ha_blackhole::info");
- records= 0;
- deleted= 0;
- errkey= 0;
- mean_rec_length= 0;
- data_file_length= 0;
- index_file_length= 0;
- max_data_file_length= 0;
- delete_length= 0;
+ bzero((char*) &stats, sizeof(stats));
if (flag & HA_STATUS_AUTO)
- auto_increment_value= 1;
+ stats.auto_increment_value= 1;
DBUG_VOID_RETURN;
}
@@ -256,15 +201,28 @@ int ha_blackhole::index_last(byte * buf)
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
+static int blackhole_init()
+{
+ blackhole_hton.state= SHOW_OPTION_YES;
+ blackhole_hton.db_type= DB_TYPE_BLACKHOLE_DB;
+ blackhole_hton.create= blackhole_create_handler;
+ blackhole_hton.flags= HTON_CAN_RECREATE | HTON_ALTER_CANNOT_CREATE;
+ return 0;
+}
+
+struct st_mysql_storage_engine blackhole_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &blackhole_hton };
+
mysql_declare_plugin(blackhole)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &blackhole_hton,
- blackhole_hton_name,
+ &blackhole_storage_engine,
+ "BLACKHOLE",
"MySQL AB",
- blackhole_hton_comment,
- NULL, /* Plugin Init */
+ "/dev/null storage engine (anything you write to it disappears)",
+ blackhole_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
+ 0
}
mysql_declare_plugin_end;
diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h
index 15e12659aa0..55c26f6f02e 100644
--- a/storage/blackhole/ha_blackhole.h
+++ b/storage/blackhole/ha_blackhole.h
@@ -40,12 +40,11 @@ public:
*/
const char *index_type(uint key_number);
const char **bas_ext() const;
- ulong table_flags() const
+ ulonglong table_flags() const
{
return(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
- HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
- HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED);
+ HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
+ HA_FILE_BASED | HA_CAN_GEOMETRY | HA_CAN_INSERT_DELAYED);
}
ulong index_flags(uint inx, uint part, bool all_parts) const
{
@@ -84,5 +83,4 @@ public:
THR_LOCK_DATA **store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
- bool has_transactions() { return 1; }
};
diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
index de69df90ed5..e5ddba7540d 100644
--- a/storage/csv/ha_tina.cc
+++ b/storage/csv/ha_tina.cc
@@ -74,48 +74,10 @@ static int write_meta_file(File meta_file, ha_rows rows, bool dirty);
pthread_mutex_t tina_mutex;
static HASH tina_open_tables;
static int tina_init= 0;
-static handler *tina_create_handler(TABLE_SHARE *table);
+static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static int tina_init_func();
-static const char tina_hton_name[]= "CSV";
-static const char tina_hton_comment[]= "CSV storage engine";
-
-handlerton tina_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- tina_hton_name,
- SHOW_OPTION_YES,
- tina_hton_comment,
- DB_TYPE_CSV_DB,
- (bool (*)()) tina_init_func,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- tina_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- tina_end, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter Tablespace */
- NULL, /* Fill FILES Table */
- HTON_CAN_RECREATE,
- NULL, /* binlog_func */
- NULL /* binlog_log_query */
-};
+handlerton tina_hton;
/*****************************************************************************
** TINA tables
@@ -146,6 +108,11 @@ static byte* tina_get_key(TINA_SHARE *share,uint *length,
int get_mmap(TINA_SHARE *share, int write)
{
DBUG_ENTER("ha_tina::get_mmap");
+#ifdef __NETWARE__
+ my_message(errno, "Sorry, no mmap() on Netware", 0);
+ DBUG_ASSERT(0);
+ DBUG_RETURN(1);
+#else
if (share->mapped_file && my_munmap(share->mapped_file,
share->file_stat.st_size))
DBUG_RETURN(1);
@@ -180,6 +147,7 @@ int get_mmap(TINA_SHARE *share, int write)
share->mapped_file= NULL;
DBUG_RETURN(0);
+#endif /* __NETWARE__ */
}
@@ -191,6 +159,11 @@ static int tina_init_func()
VOID(pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST));
(void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
(hash_get_key) tina_get_key,0,0);
+ tina_hton.state= SHOW_OPTION_YES;
+ tina_hton.db_type= DB_TYPE_CSV_DB;
+ tina_hton.create= tina_create_handler;
+ tina_hton.panic= tina_end;
+ tina_hton.flags= HTON_CAN_RECREATE;
}
return 0;
}
@@ -466,21 +439,35 @@ int tina_end(ha_panic_function type)
/*
Finds the end of a line.
- Currently only supports files written on a UNIX OS.
+ Supports DOS, Unix, or Mac OS line endings.
*/
-byte * find_eoln(byte *data, off_t begin, off_t end)
+byte * find_eoln(byte *data, off_t begin, off_t end, int *eoln_len)
{
+ off_t dataend= begin;
+ *eoln_len= 0;
+
for (off_t x= begin; x < end; x++)
- if (data[x] == '\n')
- return data + x;
+ if (data[x] == '\r' || data[x] == '\n')
+ (*eoln_len)++;
+ else if (!(*eoln_len))
+ dataend++;
+ else
+ return data+dataend;
+ /*
+ if we only have one record in the file then our for loop will break
+ before we return. we should still have seen end of line markers and
+ so we just return the line here
+ */
+ if (*eoln_len > 0)
+ return data+dataend;
return 0;
}
-static handler *tina_create_handler(TABLE_SHARE *table)
+static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_tina(table);
+ return new (mem_root) ha_tina(table);
}
@@ -507,8 +494,10 @@ ha_tina::ha_tina(TABLE_SHARE *table_arg)
int ha_tina::encode_quote(byte *buf)
{
char attribute_buffer[1024];
- String attribute(attribute_buffer, sizeof(attribute_buffer), &my_charset_bin);
+ String attribute(attribute_buffer, sizeof(attribute_buffer),
+ &my_charset_bin);
+ my_bitmap_map *org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
buffer.length(0);
for (Field **field=table->field ; *field ; field++)
{
@@ -569,6 +558,7 @@ int ha_tina::encode_quote(byte *buf)
buffer.append('\n');
//buffer.replace(buffer.length(), 0, "\n", 1);
+ dbug_tmp_restore_column_map(table->read_set, org_bitmap);
return (buffer.length());
}
@@ -621,6 +611,8 @@ int ha_tina::find_current_row(byte *buf)
{
byte *mapped_ptr;
byte *end_ptr;
+ int eoln_len;
+ my_bitmap_map *org_bitmap;
DBUG_ENTER("ha_tina::find_current_row");
mapped_ptr= (byte *)share->mapped_file + current_position;
@@ -630,16 +622,22 @@ int ha_tina::find_current_row(byte *buf)
not to conflict with undergoing concurrent insert.
*/
if ((end_ptr= find_eoln(share->mapped_file, current_position,
- local_saved_data_file_length)) == 0)
+ local_saved_data_file_length, &eoln_len)) == 0)
DBUG_RETURN(HA_ERR_END_OF_FILE);
+ /* Avoid asserts in ::store() for columns that are not going to be updated */
+ org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
+
for (Field **field=table->field ; *field ; field++)
{
buffer.length(0);
if (*mapped_ptr == '"')
mapped_ptr++; // Increment past the first quote
else
+ {
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+ }
for(;mapped_ptr != end_ptr; mapped_ptr++)
{
// Need to convert line feeds!
@@ -672,15 +670,20 @@ int ha_tina::find_current_row(byte *buf)
we are working with a damaged file.
*/
if (mapped_ptr == end_ptr -1)
+ {
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+ }
buffer.append(*mapped_ptr);
}
}
- (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
+ if (bitmap_is_set(table->read_set, (*field)->field_index))
+ (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
}
- next_position= (end_ptr - share->mapped_file)+1;
+ next_position= (end_ptr - share->mapped_file)+eoln_len;
/* Maybe use \N for null? */
memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
DBUG_RETURN(0);
}
@@ -898,7 +901,7 @@ int ha_tina::write_row(byte * buf)
update_status();
pthread_mutex_unlock(&share->mutex);
- records++;
+ stats.records++;
DBUG_RETURN(0);
}
@@ -957,7 +960,7 @@ int ha_tina::delete_row(const byte * buf)
if (chain_append())
DBUG_RETURN(-1);
- --records;
+ stats.records--;
/* DELETE should never happen on the log table */
DBUG_ASSERT(!share->is_log_table);
@@ -1005,7 +1008,7 @@ int ha_tina::rnd_init(bool scan)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
current_position= next_position= 0;
- records= 0;
+ stats.records= 0;
records_is_known= 0;
chain_ptr= chain;
#ifdef HAVE_MADVISE
@@ -1047,7 +1050,7 @@ int ha_tina::rnd_next(byte *buf)
if ((rc= find_current_row(buf)))
DBUG_RETURN(rc);
- records++;
+ stats.records++;
DBUG_RETURN(0);
}
@@ -1090,8 +1093,8 @@ void ha_tina::info(uint flag)
{
DBUG_ENTER("ha_tina::info");
/* This is a lie, but you don't want the optimizer to see zero or 1 */
- if (!records_is_known && records < 2)
- records= 2;
+ if (!records_is_known && stats.records < 2)
+ stats.records= 2;
DBUG_VOID_RETURN;
}
@@ -1204,6 +1207,8 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
goto end;
}
+ /* Don't assert in field::val() functions */
+ table->use_all_columns();
if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -1307,7 +1312,7 @@ int ha_tina::delete_all_rows()
if (get_mmap(share, 0) > 0)
DBUG_RETURN(-1);
- records=0;
+ stats.records=0;
DBUG_RETURN(rc);
}
@@ -1401,17 +1406,20 @@ bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
+struct st_mysql_storage_engine csv_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &tina_hton };
mysql_declare_plugin(csv)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &tina_hton,
- tina_hton_name,
+ &csv_storage_engine,
+ "CSV",
"Brian Aker, MySQL AB",
- tina_hton_comment,
+ "CSV storage engine",
tina_init_func, /* Plugin Init */
tina_done_func, /* Plugin Deinit */
0x0100 /* 1.0 */,
+ 0
}
mysql_declare_plugin_end;
diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h
index d155a614780..d3a8c5092b6 100644
--- a/storage/csv/ha_tina.h
+++ b/storage/csv/ha_tina.h
@@ -87,14 +87,16 @@ public:
const char *table_type() const { return "CSV"; }
const char *index_type(uint inx) { return "NONE"; }
const char **bas_ext() const;
- ulong table_flags() const
+ ulonglong table_flags() const
{
- return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT |
- HA_NO_AUTO_INCREMENT );
+ return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT);
}
ulong index_flags(uint idx, uint part, bool all_parts) const
{
- /* We will never have indexes so this will never be called(AKA we return zero) */
+ /*
+ We will never have indexes so this will never be called(AKA we return
+ zero)
+ */
return 0;
}
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -104,7 +106,7 @@ public:
/*
Called in test_quick_select to determine if indexes should be used.
*/
- virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
+ virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
/* The next method will never be called */
virtual bool fast_key_read() { return 1;}
/*
diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc
index 2ce543dfbb0..feabad2e356 100644
--- a/storage/example/ha_example.cc
+++ b/storage/example/ha_example.cc
@@ -72,51 +72,12 @@
#include <mysql/plugin.h>
-static handler* example_create_handler(TABLE_SHARE *table);
+static handler *example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
static int example_init_func();
static bool example_init_func_for_handlerton();
static int example_panic(enum ha_panic_function flag);
-static const char example_hton_name[]= "EXAMPLE";
-static const char example_hton_comment[]= "Example storage engine";
-
-handlerton example_hton= {
- MYSQL_HANDLERTON_INTERFACE_VERSION,
- example_hton_name,
- SHOW_OPTION_YES,
- example_hton_comment,
- DB_TYPE_EXAMPLE_DB,
- example_init_func_for_handlerton,
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- example_create_handler, /* Create a new handler */
- NULL, /* Drop a database */
- example_panic, /* Panic call */
- NULL, /* Start Consistent Snapshot */
- NULL, /* Flush logs */
- NULL, /* Show status */
- NULL, /* Partition flags */
- NULL, /* Alter table flags */
- NULL, /* Alter tablespace */
- NULL, /* Fill Files table */
- HTON_CAN_RECREATE,
- NULL,
- NULL,
- NULL,
-};
+handlerton example_hton;
/* Variables for example share methods */
static HASH example_open_tables; // Hash used to track open tables
@@ -143,6 +104,11 @@ static int example_init_func()
VOID(pthread_mutex_init(&example_mutex,MY_MUTEX_INIT_FAST));
(void) hash_init(&example_open_tables,system_charset_info,32,0,0,
(hash_get_key) example_get_key,0,0);
+
+ example_hton.state= SHOW_OPTION_YES;
+ example_hton.db_type= DB_TYPE_EXAMPLE_DB;
+ example_hton.create= example_create_handler;
+ example_hton.flags= HTON_CAN_RECREATE;
}
DBUG_RETURN(0);
}
@@ -163,17 +129,6 @@ static int example_done_func()
DBUG_RETURN(0);
}
-static bool example_init_func_for_handlerton()
-{
- return example_init_func();
-}
-
-static int example_panic(enum ha_panic_function flag)
-{
- return example_done_func();
-}
-
-
/*
Example of simple lock controls. The "share" it creates is structure we will
pass to each example handler. Do you have to have one of these? Well, you have
@@ -244,9 +199,9 @@ static int free_share(EXAMPLE_SHARE *share)
}
-static handler* example_create_handler(TABLE_SHARE *table)
+static handler* example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
- return new ha_example(table);
+ return new (mem_root) ha_example(table);
}
@@ -741,21 +696,25 @@ int ha_example::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info)
{
DBUG_ENTER("ha_example::create");
- /* This is not implemented but we want someone to be able that it works. */
+ /* This is not implemented but we want someone to be able to see that it works. */
DBUG_RETURN(0);
}
+struct st_mysql_storage_engine example_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &example_hton };
+
mysql_declare_plugin(example)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
- &example_hton,
- example_hton_name,
+ &example_storage_engine,
+ "EXAMPLE",
"Brian Aker, MySQL AB",
- example_hton_comment,
+ "Example storage engine",
example_init_func, /* Plugin Init */
example_done_func, /* Plugin Deinit */
0x0001 /* 0.1 */,
+ 0
}
mysql_declare_plugin_end;
diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h
index 139a50a3281..956dc62311c 100644
--- a/storage/example/ha_example.h
+++ b/storage/example/ha_example.h
@@ -62,7 +62,7 @@ public:
implements. The current table flags are documented in
handler.h
*/
- ulong table_flags() const
+ ulonglong table_flags() const
{
return 0;
}
@@ -97,7 +97,7 @@ public:
/*
Called in test_quick_select to determine if indexes should be used.
*/
- virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
+ virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
/*
The next method will never be called if you do not implement indexes.
*/
diff --git a/storage/heap/hp_create.c b/storage/heap/hp_create.c
index 329f4b7fa2d..8e185a60262 100644
--- a/storage/heap/hp_create.c
+++ b/storage/heap/hp_create.c
@@ -85,6 +85,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (!my_binary_compare(keyinfo->seg[j].charset))
keyinfo->flag|= HA_END_SPACE_KEY;
keyinfo->flag|= HA_VAR_LENGTH_KEY;
+ length+= 2;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 1;
break;
@@ -95,6 +96,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (!my_binary_compare(keyinfo->seg[j].charset))
keyinfo->flag|= HA_END_SPACE_KEY;
keyinfo->flag|= HA_VAR_LENGTH_KEY;
+ length+= 2;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 2;
/*
diff --git a/storage/heap/hp_extra.c b/storage/heap/hp_extra.c
index dd41d6c5f19..abb632707f2 100644
--- a/storage/heap/hp_extra.c
+++ b/storage/heap/hp_extra.c
@@ -32,13 +32,8 @@ int heap_extra(register HP_INFO *info, enum ha_extra_function function)
DBUG_ENTER("heap_extra");
switch (function) {
- case HA_EXTRA_RESET:
case HA_EXTRA_RESET_STATE:
- info->lastinx= -1;
- info->current_record= (ulong) ~0L;
- info->current_hash_ptr=0;
- info->update=0;
- break;
+ heap_reset(info);
case HA_EXTRA_NO_READCHECK:
info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
break;
@@ -56,6 +51,16 @@ int heap_extra(register HP_INFO *info, enum ha_extra_function function)
} /* heap_extra */
+int heap_reset(HP_INFO *info)
+{
+ info->lastinx= -1;
+ info->current_record= (ulong) ~0L;
+ info->current_hash_ptr=0;
+ info->update=0;
+ return 0;
+}
+
+
/*
Start/Stop Inserting Duplicates Into a Table, WL#1648.
*/
diff --git a/storage/heap/hp_test2.c b/storage/heap/hp_test2.c
index a74872dbd11..8d2a8bc3da2 100644
--- a/storage/heap/hp_test2.c
+++ b/storage/heap/hp_test2.c
@@ -469,7 +469,7 @@ int main(int argc, char *argv[])
#endif
printf("- Read through all records with scan\n");
- if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
+ if (heap_reset(file) || heap_extra(file,HA_EXTRA_CACHE))
{
puts("got error from heap_extra");
goto end;
diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c
index a60d32eecb6..bc94e3bfae4 100644
--- a/storage/heap/hp_write.c
+++ b/storage/heap/hp_write.c
@@ -105,7 +105,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *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_SAME | SEARCH_UPDATE;
+ custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
keyinfo->rb_tree.flag= TREE_NO_DUPS;
}
else
diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c
index 8d48f533203..cb4005d5c84 100644
--- a/storage/myisam/ft_boolean_search.c
+++ b/storage/myisam/ft_boolean_search.c
@@ -160,7 +160,6 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
typedef struct st_my_ftb_param
{
- MYSQL_FTPARSER_PARAM *up;
FTB *ftb;
FTB_EXPR *ftbe;
byte *up_quot;
@@ -168,10 +167,11 @@ typedef struct st_my_ftb_param
} MY_FTB_PARAM;
-static int ftb_query_add_word(void *param, char *word, int word_len,
+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= (MY_FTB_PARAM *)param;
+ MY_FTB_PARAM *ftb_param= param->mysql_ftparam;
FTB_WORD *ftbw;
FTB_EXPR *ftbe, *tmp_expr;
FT_WORD *phrase_word;
@@ -269,9 +269,10 @@ static int ftb_query_add_word(void *param, char *word, int word_len,
}
-static int ftb_parse_query_internal(void *param, char *query, int len)
+static int ftb_parse_query_internal(MYSQL_FTPARSER_PARAM *param,
+ char *query, int len)
{
- MY_FTB_PARAM *ftb_param= (MY_FTB_PARAM *)param;
+ MY_FTB_PARAM *ftb_param= param->mysql_ftparam;
MYSQL_FTPARSER_BOOLEAN_INFO info;
CHARSET_INFO *cs= ftb_param->ftb->charset;
char **start= &query;
@@ -281,7 +282,7 @@ static int ftb_parse_query_internal(void *param, char *query, int len)
info.prev= ' ';
info.quot= 0;
while (ft_get_word(cs, start, end, &w, &info))
- ftb_param->up->mysql_add_word(param, w.pos, w.len, &info);
+ param->mysql_add_word(param, w.pos, w.len, &info);
return(0);
}
@@ -299,7 +300,6 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len,
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
DBUG_VOID_RETURN;
- ftb_param.up= param;
ftb_param.ftb= ftb;
ftb_param.depth= 0;
ftb_param.ftbe= ftb->root;
@@ -311,6 +311,7 @@ static void _ftb_parse_query(FTB *ftb, byte *query, uint len,
param->cs= ftb->charset;
param->doc= query;
param->length= len;
+ param->flags= 0;
param->mode= MYSQL_FTPARSER_FULL_BOOLEAN_INFO;
parser->parse(param);
DBUG_VOID_RETURN;
@@ -571,7 +572,6 @@ err:
typedef struct st_my_ftb_phrase_param
{
- MYSQL_FTPARSER_PARAM *up;
LIST *phrase;
LIST *document;
CHARSET_INFO *cs;
@@ -581,10 +581,11 @@ typedef struct st_my_ftb_phrase_param
} MY_FTB_PHRASE_PARAM;
-static int ftb_phrase_add_word(void *param, char *word, int word_len,
+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= (MY_FTB_PHRASE_PARAM *)param;
+ MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
FT_WORD *w= (FT_WORD *)phrase_param->document->data;
LIST *phrase, *document;
w->pos= word;
@@ -602,8 +603,9 @@ static int ftb_phrase_add_word(void *param, char *word, int word_len,
{
FT_WORD *phrase_word= (FT_WORD *)phrase->data;
FT_WORD *document_word= (FT_WORD *)document->data;
- if (my_strnncoll(phrase_param->cs, phrase_word->pos, phrase_word->len,
- document_word->pos, document_word->len))
+ 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++;
@@ -611,14 +613,15 @@ static int ftb_phrase_add_word(void *param, char *word, int word_len,
}
-static int ftb_check_phrase_internal(void *param, char *document, int len)
+static int ftb_check_phrase_internal(MYSQL_FTPARSER_PARAM *param,
+ char *document, int len)
{
FT_WORD word;
- MY_FTB_PHRASE_PARAM *phrase_param= (MY_FTB_PHRASE_PARAM *)param;
+ MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
const char *docend= document + len;
while (ft_simple_get_word(phrase_param->cs, &document, docend, &word, FALSE))
{
- phrase_param->up->mysql_add_word(param, word.pos, word.len, 0);
+ param->mysql_add_word(param, word.pos, word.len, 0);
if (phrase_param->match)
return 1;
}
@@ -651,7 +654,6 @@ static int _ftb_check_phrase(FTB *ftb, const byte *document, uint len,
if (! (param= ftparser_call_initializer(ftb->info, ftb->keynr, 1)))
DBUG_RETURN(0);
- ftb_param.up= param;
ftb_param.phrase= ftbe->phrase;
ftb_param.document= ftbe->document;
ftb_param.cs= ftb->charset;
@@ -665,6 +667,7 @@ static int _ftb_check_phrase(FTB *ftb, const byte *document, uint len,
param->cs= ftb->charset;
param->doc= (byte *)document;
param->length= len;
+ param->flags= 0;
param->mode= MYSQL_FTPARSER_WITH_STOPWORDS;
parser->parse(param);
DBUG_RETURN(ftb_param.match ? 1 : 0);
@@ -820,16 +823,16 @@ err:
typedef struct st_my_ftb_find_param
{
- MYSQL_FTPARSER_PARAM *up;
FT_INFO *ftb;
FT_SEG_ITERATOR *ftsi;
} MY_FTB_FIND_PARAM;
-static int ftb_find_relevance_add_word(void *param, char *word, int len,
+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= (MY_FTB_FIND_PARAM *)param;
+ MY_FTB_FIND_PARAM *ftb_param= param->mysql_ftparam;
FT_INFO *ftb= ftb_param->ftb;
FTB_WORD *ftbw;
int a, b, c;
@@ -859,14 +862,15 @@ static int ftb_find_relevance_add_word(void *param, char *word, int len,
}
-static int ftb_find_relevance_parse(void *param, char *doc, int len)
+static int ftb_find_relevance_parse(MYSQL_FTPARSER_PARAM *param,
+ char *doc, int len)
{
- MY_FTB_FIND_PARAM *ftb_param=(MY_FTB_FIND_PARAM *)param;
+ MY_FTB_FIND_PARAM *ftb_param= param->mysql_ftparam;
FT_INFO *ftb= ftb_param->ftb;
char *end= doc + len;
FT_WORD w;
while (ft_simple_get_word(ftb->charset, &doc, end, &w, TRUE))
- ftb_param->up->mysql_add_word(param, w.pos, w.len, 0);
+ param->mysql_add_word(param, w.pos, w.len, 0);
return(0);
}
@@ -910,12 +914,12 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
_mi_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi);
memcpy(&ftsi2, &ftsi, sizeof(ftsi));
- ftb_param.up= param;
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 (_mi_ft_segiterator(&ftsi))
diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c
index b8207c1c3d0..53a01003dcd 100644
--- a/storage/myisam/ft_nlq_search.c
+++ b/storage/myisam/ft_nlq_search.c
@@ -235,7 +235,9 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
NULL, NULL);
ft_parse_init(&wtree, aio.charset);
- if (ft_parse(&wtree, query, query_len, 0, parser, ftparser_param))
+ ftparser_param->flags= 0;
+ if (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,
@@ -255,7 +257,9 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
if (!(*info->read_record)(info,docid,record))
{
info->update|= HA_STATE_AKTIV;
- _mi_ft_parse(&wtree, info, keynr, record, 1, ftparser_param);
+ ftparser_param->flags= MYSQL_FTFLAGS_NEED_COPY;
+ _mi_ft_parse(&wtree, info, keynr, record, ftparser_param,
+ &wtree.mem_root);
}
}
delete_queue(&best);
diff --git a/storage/myisam/ft_parser.c b/storage/myisam/ft_parser.c
index 89ede813a2b..38ac744d4a8 100644
--- a/storage/myisam/ft_parser.c
+++ b/storage/myisam/ft_parser.c
@@ -24,15 +24,12 @@ typedef struct st_ft_docstat {
double sum;
} FT_DOCSTAT;
-
typedef struct st_my_ft_parser_param
{
- MYSQL_FTPARSER_PARAM *up;
- TREE *wtree;
- my_bool with_alloc;
+ 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 mi_compare_text(cs, (uchar*) w1->pos, w1->len,
@@ -49,14 +46,14 @@ static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
/* transforms tree of words into the array, applying normalization */
-FT_WORD * ft_linearize(TREE *wtree)
+FT_WORD * ft_linearize(TREE *wtree, MEM_ROOT *mem_root)
{
FT_WORD *wlist,*p;
FT_DOCSTAT docstat;
DBUG_ENTER("ft_linearize");
- if ((wlist=(FT_WORD *) my_malloc(sizeof(FT_WORD)*
- (1+wtree->elements_in_tree),MYF(0))))
+ 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;
@@ -241,19 +238,20 @@ void ft_parse_init(TREE *wtree, CHARSET_INFO *cs)
}
-static int ft_add_word(void *param, byte *word, uint word_len,
+static int 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("ft_add_word");
- wtree= ((MY_FT_PARSER_PARAM *)param)->wtree;
- if (((MY_FT_PARSER_PARAM *)param)->with_alloc)
+ wtree= ft_param->wtree;
+ if (param->flags & MYSQL_FTFLAGS_NEED_COPY)
{
byte *ptr;
- /* allocating the data in the tree - to avoid mallocs and frees */
DBUG_ASSERT(wtree->with_delete == 0);
- ptr= (byte *)alloc_root(&wtree->mem_root, word_len);
+ ptr= (byte *)alloc_root(ft_param->mem_root, word_len);
memcpy(ptr, word, word_len);
w.pos= ptr;
}
@@ -269,32 +267,32 @@ static int ft_add_word(void *param, byte *word, uint word_len,
}
-static int ft_parse_internal(void *param, byte *doc, int doc_len)
+static int ft_parse_internal(MYSQL_FTPARSER_PARAM *param,
+ byte *doc, int doc_len)
{
byte *end=doc+doc_len;
- MY_FT_PARSER_PARAM *ft_param=(MY_FT_PARSER_PARAM *)param;
+ MY_FT_PARSER_PARAM *ft_param=param->mysql_ftparam;
TREE *wtree= ft_param->wtree;
FT_WORD w;
DBUG_ENTER("ft_parse_internal");
while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
- if (ft_param->up->mysql_add_word(param, w.pos, w.len, 0))
+ if (param->mysql_add_word(param, w.pos, w.len, 0))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
-int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
+int ft_parse(TREE *wtree, byte *doc, int doclen,
struct st_mysql_ftparser *parser,
- MYSQL_FTPARSER_PARAM *param)
+ MYSQL_FTPARSER_PARAM *param, MEM_ROOT *mem_root)
{
MY_FT_PARSER_PARAM my_param;
DBUG_ENTER("ft_parse");
DBUG_ASSERT(parser);
- my_param.up= param;
my_param.wtree= wtree;
- my_param.with_alloc= with_alloc;
+ my_param.mem_root= mem_root;
param->mysql_parse= ft_parse_internal;
param->mysql_add_word= ft_add_word;
@@ -356,6 +354,7 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
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;
}
@@ -387,6 +386,7 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
void ftparser_call_deinitializer(MI_INFO *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++)
diff --git a/storage/myisam/ft_static.c b/storage/myisam/ft_static.c
index 6cfb0d59e62..61bb7b3c1f7 100644
--- a/storage/myisam/ft_static.c
+++ b/storage/myisam/ft_static.c
@@ -629,7 +629,7 @@ const char *ft_precompiled_stopwords[] = {
static int ft_default_parser_parse(MYSQL_FTPARSER_PARAM *param)
{
- return param->mysql_parse(param->mysql_ftparam, param->doc, param->length);
+ return param->mysql_parse(param, param->doc, param->length);
}
struct st_mysql_ftparser ft_default_parser=
diff --git a/storage/myisam/ft_update.c b/storage/myisam/ft_update.c
index f5501792dcd..08d605dbcc2 100644
--- a/storage/myisam/ft_update.c
+++ b/storage/myisam/ft_update.c
@@ -77,7 +77,7 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
{
uint pack_length= (ftsi->seg->bit_start);
ftsi->len= (pack_length == 1 ? (uint) *(uchar*) ftsi->pos :
- uint2korr(ftsi->pos));
+ uint2korr(ftsi->pos));
ftsi->pos+= pack_length; /* Skip VARCHAR length */
DBUG_RETURN(1);
}
@@ -95,9 +95,8 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
/* parses a document i.e. calls ft_parse for every keyseg */
-uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr,
- const byte *record, my_bool with_alloc,
- MYSQL_FTPARSER_PARAM *param)
+uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record,
+ MYSQL_FTPARSER_PARAM *param, MEM_ROOT *mem_root)
{
FT_SEG_ITERATOR ftsi;
struct st_mysql_ftparser *parser;
@@ -110,14 +109,14 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr,
while (_mi_ft_segiterator(&ftsi))
{
if (ftsi.pos)
- if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, with_alloc, parser,
- param))
+ if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, parser, param, mem_root))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
-FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record)
+FT_WORD *_mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record,
+ MEM_ROOT *mem_root)
{
TREE ptree;
MYSQL_FTPARSER_PARAM *param;
@@ -125,10 +124,11 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record)
if (! (param= ftparser_call_initializer(info, keynr, 0)))
DBUG_RETURN(NULL);
bzero((char*) &ptree, sizeof(ptree));
- if (_mi_ft_parse(&ptree, info, keynr, record, 0, param))
+ param->flags= 0;
+ if (_mi_ft_parse(&ptree, info, keynr, record, param, mem_root))
DBUG_RETURN(NULL);
- DBUG_RETURN(ft_linearize(&ptree));
+ DBUG_RETURN(ft_linearize(&ptree, mem_root));
}
static int _mi_ft_store(MI_INFO *info, uint keynr, byte *keybuf,
@@ -206,10 +206,11 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
int cmp, cmp2;
DBUG_ENTER("_mi_ft_update");
- if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, oldrec)))
- goto err0;
- if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, newrec)))
- goto err1;
+ if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, oldrec,
+ &info->ft_memroot)) ||
+ !(new_word=newlist=_mi_ft_parserecord(info, keynr, newrec,
+ &info->ft_memroot)))
+ goto err;
error=0;
while(old_word->pos && new_word->pos)
@@ -222,13 +223,13 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
{
key_length=_ft_make_key(info,keynr,keybuf,old_word,pos);
if ((error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length)))
- goto err2;
+ goto err;
}
if (cmp > 0 || cmp2)
{
key_length=_ft_make_key(info,keynr,keybuf,new_word,pos);
if ((error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length)))
- goto err2;
+ goto err;
}
if (cmp<=0) old_word++;
if (cmp>=0) new_word++;
@@ -238,11 +239,8 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
else if (new_word->pos)
error=_mi_ft_store(info,keynr,keybuf,new_word,pos);
-err2:
- my_free((char*) newlist,MYF(0));
-err1:
- my_free((char*) oldlist,MYF(0));
-err0:
+err:
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
DBUG_RETURN(error);
}
@@ -255,12 +253,13 @@ int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
int error= -1;
FT_WORD *wlist;
DBUG_ENTER("_mi_ft_add");
+ DBUG_PRINT("enter",("keynr: %d",keynr));
- if ((wlist=_mi_ft_parserecord(info, keynr, record)))
- {
+ if ((wlist=_mi_ft_parserecord(info, keynr, record, &info->ft_memroot)))
error=_mi_ft_store(info,keynr,keybuf,wlist,pos);
- my_free((char*) wlist,MYF(0));
- }
+
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
+ DBUG_PRINT("exit",("Return: %d",error));
DBUG_RETURN(error);
}
@@ -275,11 +274,10 @@ int _mi_ft_del(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
DBUG_ENTER("_mi_ft_del");
DBUG_PRINT("enter",("keynr: %d",keynr));
- if ((wlist=_mi_ft_parserecord(info, keynr, record)))
- {
+ if ((wlist=_mi_ft_parserecord(info, keynr, record, &info->ft_memroot)))
error=_mi_ft_erase(info,keynr,keybuf,wlist,pos);
- my_free((char*) wlist,MYF(0));
- }
+
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
DBUG_PRINT("exit",("Return: %d",error));
DBUG_RETURN(error);
}
diff --git a/storage/myisam/ftdefs.h b/storage/myisam/ftdefs.h
index 2c4cfa1ffd6..108faf4f1a3 100644
--- a/storage/myisam/ftdefs.h
+++ b/storage/myisam/ftdefs.h
@@ -30,6 +30,8 @@
#define FT_MAX_WORD_LEN_FOR_SORT 31
+#define FTPARSER_MEMROOT_ALLOC_SIZE 65536
+
#define COMPILE_STOPWORDS_IN
/* Interested readers may consult SMART
@@ -119,12 +121,12 @@ void _mi_ft_segiterator_dummy_init(const byte *, uint, FT_SEG_ITERATOR *);
uint _mi_ft_segiterator(FT_SEG_ITERATOR *);
void ft_parse_init(TREE *, CHARSET_INFO *);
-int ft_parse(TREE *, byte *, int, my_bool, struct st_mysql_ftparser *parser,
- MYSQL_FTPARSER_PARAM *param);
-FT_WORD * ft_linearize(TREE *);
-FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *);
-uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *, my_bool,
- MYSQL_FTPARSER_PARAM *param);
+int ft_parse(TREE *, byte *, int, struct st_mysql_ftparser *parser,
+ MYSQL_FTPARSER_PARAM *, MEM_ROOT *);
+FT_WORD * ft_linearize(TREE *, MEM_ROOT *);
+FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *, MEM_ROOT *);
+uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *,
+ MYSQL_FTPARSER_PARAM *, MEM_ROOT *);
FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint, byte *);
FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, CHARSET_INFO *);
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index 0fa095a21db..d91597e9138 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -453,25 +453,24 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
if ((uint) share->base.auto_key -1 == key)
{
/* Check that auto_increment key is bigger than max key value */
- ulonglong save_auto_value=info->s->state.auto_increment;
- info->s->state.auto_increment=0;
+ ulonglong auto_increment;
info->lastinx=key;
_mi_read_key_record(info, 0L, info->rec_buff);
- update_auto_increment(info, info->rec_buff);
- if (info->s->state.auto_increment > save_auto_value)
+ auto_increment= retrieve_auto_increment(info, info->rec_buff);
+ if (auto_increment > info->s->state.auto_increment)
{
- mi_check_print_warning(param,
- "Auto-increment value: %s is smaller than max used value: %s",
- llstr(save_auto_value,buff2),
- llstr(info->s->state.auto_increment, buff));
+ mi_check_print_warning(param, "Auto-increment value: %s is smaller "
+ "than max used value: %s",
+ llstr(info->s->state.auto_increment,buff2),
+ llstr(auto_increment, buff));
}
if (param->testflag & T_AUTO_INC)
{
- set_if_bigger(info->s->state.auto_increment,
- param->auto_increment_value);
+ set_if_bigger(info->s->state.auto_increment,
+ auto_increment);
+ set_if_bigger(info->s->state.auto_increment,
+ param->auto_increment_value);
}
- else
- info->s->state.auto_increment=save_auto_value;
/* Check that there isn't a row with auto_increment = 0 in the table */
mi_extra(info,HA_EXTRA_KEYREAD,0);
@@ -481,8 +480,8 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
{
/* Don't count this as a real warning, as myisamchk can't correct it */
uint save=param->warning_printed;
- mi_check_print_warning(param,
- "Found row where the auto_increment column has the value 0");
+ mi_check_print_warning(param, "Found row where the auto_increment "
+ "column has the value 0");
param->warning_printed=save;
}
mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
@@ -2117,6 +2116,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
sort_param.wordlist=NULL;
+ init_alloc_root(&sort_param.wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
if (share->data_file_type == DYNAMIC_RECORD)
length=max(share->base.min_pack_length+1,share->base.min_block_length);
@@ -2179,12 +2179,36 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
{
uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
sort_param.keyinfo->seg->charset->mbmaxlen;
- sort_info.max_records=
- (ha_rows) (sort_info.filelength/ft_min_word_len+1);
+ 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 _create_index_by_sort)
+ */
+ sort_info.max_records=
+ 10*param->sort_buffer_length/sort_param.key_length;
+ }
sort_param.key_read=sort_ft_key_read;
sort_param.key_write=sort_ft_key_write;
- sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
}
else
{
@@ -2200,6 +2224,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
goto err;
}
param->calc_checksum=0; /* No need to calc glob_crc */
+ free_root(&sort_param.wordroot, MYF(0));
/* Set for next loop */
sort_info.max_records= (ha_rows) info->state->records;
@@ -2589,6 +2614,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
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;
@@ -2810,10 +2836,11 @@ static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
{
for (;;)
{
- my_free((char*) wptr, MYF(MY_ALLOW_ZERO_PTR));
+ free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error);
- if (!(wptr=_mi_ft_parserecord(info,sort_param->key,sort_param->record)))
+ if (!(wptr=_mi_ft_parserecord(info,sort_param->key,sort_param->record,
+ &sort_param->wordroot)))
DBUG_RETURN(1);
if (wptr->pos)
break;
@@ -2837,7 +2864,7 @@ static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
#endif
if (!wptr->pos)
{
- my_free((char*) sort_param->wordlist, MYF(0));
+ free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
sort_param->wordlist=0;
error=sort_write_record(sort_param);
}
@@ -4096,11 +4123,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
}
else
{
- ulonglong auto_increment= (repair_only ? info->s->state.auto_increment :
- param->auto_increment_value);
- info->s->state.auto_increment=0;
- update_auto_increment(info, record);
+ ulonglong auto_increment= retrieve_auto_increment(info, record);
set_if_bigger(info->s->state.auto_increment,auto_increment);
+ if (!repair_only)
+ set_if_bigger(info->s->state.auto_increment, param->auto_increment_value);
}
mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
my_free((char*) record, MYF(0));
diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c
index 04beb36bb47..c1ed29c4734 100644
--- a/storage/myisam/mi_extra.c
+++ b/storage/myisam/mi_extra.c
@@ -47,29 +47,6 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
DBUG_PRINT("enter",("function: %d",(int) function));
switch (function) {
- case HA_EXTRA_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);
- }
- if (share->base.blobs)
- mi_alloc_rec_buff(info, -1, &info->rec_buff);
-#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
- if (info->opt_flag & MEMMAP_USED)
- madvise(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;
- /* Fall through */
-
case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */
info->lastinx= 0; /* Use first index as def */
info->last_search_keypage=info->lastpos= HA_OFFSET_ERROR;
@@ -425,3 +402,36 @@ static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function)
}
}
+
+int mi_reset(MI_INFO *info)
+{
+ int error= 0;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_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);
+ }
+ if (share->base.blobs)
+ mi_alloc_rec_buff(info, -1, &info->rec_buff);
+#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
+ if (info->opt_flag & MEMMAP_USED)
+ madvise(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->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);
+}
diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c
index 526a733e724..01bd0c43119 100644
--- a/storage/myisam/mi_key.c
+++ b/storage/myisam/mi_key.c
@@ -507,22 +507,21 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf)
return(-1); /* Wrong data to read */
}
-
+
/*
- Update auto_increment info
+ Retrieve auto_increment info
SYNOPSIS
- update_auto_increment()
+ retrieve_auto_increment()
info MyISAM handler
record Row to update
IMPLEMENTATION
- Only replace the auto_increment value if it is higher than the previous
- one. For signed columns we don't update the auto increment value if it's
+ For signed columns we don't retrieve the auto increment value if it's
less than zero.
*/
-void update_auto_increment(MI_INFO *info,const byte *record)
+ulonglong retrieve_auto_increment(MI_INFO *info,const byte *record)
{
ulonglong value= 0; /* Store unsigned values here */
longlong s_value= 0; /* Store signed values here */
@@ -587,6 +586,5 @@ void update_auto_increment(MI_INFO *info,const byte *record)
and if s_value == 0 then value will contain either s_value or the
correct value.
*/
- set_if_bigger(info->s->state.auto_increment,
- (s_value > 0) ? (ulonglong) s_value : value);
+ return (s_value > 0) ? (ulonglong) s_value : value;
}
diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c
index 05f8459a4b4..2117e9fdf15 100644
--- a/storage/myisam/mi_search.c
+++ b/storage/myisam/mi_search.c
@@ -259,15 +259,16 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
- DBUG_PRINT("error",("Found wrong key: length: %u page: %lx end: %lx",
- length, (long) page, (long) end));
+ DBUG_PRINT("error",
+ ("Found wrong key: length: %u page: 0x%lx end: 0x%lx",
+ length, (long) page, (long) end));
DBUG_RETURN(MI_FOUND_WRONG_KEY);
}
if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
not_used)) >= 0)
break;
#ifdef EXTRA_DEBUG
- DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d", (long) page, t_buff,
+ DBUG_PRINT("loop",("page: 0x%lx key: '%s' flag: %d", (long) page, t_buff,
flag));
#endif
memcpy(buff,t_buff,length);
@@ -276,7 +277,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
if (flag == 0)
memcpy(buff,t_buff,length); /* Result is first key */
*last_key= page == end;
- DBUG_PRINT("exit",("flag: %d ret_pos: %lx", flag, (long) *ret_pos));
+ DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
DBUG_RETURN(flag);
} /* _mi_seq_search */
@@ -416,8 +417,9 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
- DBUG_PRINT("error",("Found wrong key: length: %u page: %lx end: %lx",
- length, (long) page, (long) end));
+ DBUG_PRINT("error",
+ ("Found wrong key: length: %u page: 0x%lx end: %lx",
+ length, (long) page, (long) end));
DBUG_RETURN(MI_FOUND_WRONG_KEY);
}
@@ -551,7 +553,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
*last_key= page == end;
- DBUG_PRINT("exit",("flag: %d ret_pos: %lx", flag, (long) *ret_pos));
+ DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
DBUG_RETURN(flag);
} /* _mi_prefix_search */
@@ -813,7 +815,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (length > keyseg->length)
{
DBUG_PRINT("error",
- ("Found too long null packed key: %u of %u at %lx",
+ ("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);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
@@ -870,7 +872,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
}
if (length > (uint) keyseg->length)
{
- DBUG_PRINT("error",("Found too long packed key: %u of %u at %lx",
+ 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);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
@@ -936,8 +938,9 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (length > keyinfo->maxlength)
{
- DBUG_PRINT("error",("Found too long binary packed key: %u of %u at %lx",
- length, keyinfo->maxlength, (long) *page_pos));
+ 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);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
@@ -984,7 +987,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
length-=tmp;
from=page; from_end=page_end;
}
- DBUG_PRINT("info",("key: %lx from: %lx length: %u",
+ DBUG_PRINT("info",("key: 0x%lx from: 0x%lx length: %u",
(long) key, (long) from, length));
memmove((byte*) key, (byte*) from, (size_t) length);
key+=length;
@@ -1042,7 +1045,7 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
}
}
}
- DBUG_PRINT("exit",("page: %lx length: %u", (long) page,
+ DBUG_PRINT("exit",("page: 0x%lx length: %u", (long) page,
*return_key_length));
DBUG_RETURN(page);
} /* _mi_get_key */
@@ -1095,7 +1098,8 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
uint nod_flag;
uchar *lastpos;
DBUG_ENTER("_mi_get_last_key");
- DBUG_PRINT("enter",("page: %lx endpos: %lx", (long) page, (long) endpos));
+ DBUG_PRINT("enter",("page: 0x%lx endpos: 0x%lx", (long) page,
+ (long) endpos));
nod_flag=mi_test_if_nod(page);
if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
@@ -1115,7 +1119,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey);
if (*return_key_length == 0)
{
- DBUG_PRINT("error",("Couldn't find last key: page: %lx",
+ DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
(long) page));
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
@@ -1123,7 +1127,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
}
}
}
- DBUG_PRINT("exit",("lastpos: %lx length: %u", (long) lastpos,
+ DBUG_PRINT("exit",("lastpos: 0x%lx length: %u", (long) lastpos,
*return_key_length));
DBUG_RETURN(lastpos);
} /* _mi_get_last_key */
@@ -1660,7 +1664,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
ref_length=0;
next_length_pack=0;
}
- DBUG_PRINT("test",("length: %d next_key: %lx", length,
+ DBUG_PRINT("test",("length: %d next_key: 0x%lx", length,
(long) next_key));
{
diff --git a/storage/myisam/mi_test2.c b/storage/myisam/mi_test2.c
index 357ebb1b9bc..357128b7a40 100644
--- a/storage/myisam/mi_test2.c
+++ b/storage/myisam/mi_test2.c
@@ -708,7 +708,7 @@ int main(int argc, char *argv[])
if (!silent)
printf("- mi_extra(CACHE) + mi_rrnd.... + mi_extra(NO_CACHE)\n");
- if (mi_extra(file,HA_EXTRA_RESET,0) || mi_extra(file,HA_EXTRA_CACHE,0))
+ if (mi_reset(file) || mi_extra(file,HA_EXTRA_CACHE,0))
{
if (locking || (!use_blob && !pack_fields))
{
@@ -751,7 +751,7 @@ int main(int argc, char *argv[])
DBUG_PRINT("progpos",("Removing keys"));
lastpos = HA_OFFSET_ERROR;
/* DBUG_POP(); */
- mi_extra(file,HA_EXTRA_RESET,0);
+ mi_reset(file);
found_parts=0;
while ((error=mi_rrnd(file,read_record,HA_OFFSET_ERROR)) !=
HA_ERR_END_OF_FILE)
diff --git a/storage/myisam/mi_update.c b/storage/myisam/mi_update.c
index 937c9983b45..f8b5cf55406 100644
--- a/storage/myisam/mi_update.c
+++ b/storage/myisam/mi_update.c
@@ -164,7 +164,8 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
key_changed|= HA_STATE_CHANGED; /* Must update index file */
}
if (auto_key_changed)
- update_auto_increment(info,newrec);
+ set_if_bigger(info->s->state.auto_increment,
+ retrieve_auto_increment(info, newrec));
if (share->calc_checksum)
info->state->checksum+=(info->checksum - old_checksum);
diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c
index 5e79b2937cc..9ab8753f6d7 100644
--- a/storage/myisam/mi_write.c
+++ b/storage/myisam/mi_write.c
@@ -149,7 +149,8 @@ int mi_write(MI_INFO *info, byte *record)
info->state->checksum+=info->checksum;
}
if (share->base.auto_key)
- update_auto_increment(info,record);
+ set_if_bigger(info->s->state.auto_increment,
+ retrieve_auto_increment(info, record));
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
HA_STATE_ROW_CHANGED);
info->state->records++;
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index 0b450de9c03..baab34b4b67 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -235,13 +235,14 @@ struct st_myisam_info {
/* accumulate indexfile changes between write's */
TREE *bulk_insert;
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
- 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 */
- byte *rec_buff; /* Tempbuff for recordpack */
- uchar *int_keypos, /* Save position for next/previous */
+ 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 */
+ byte *rec_buff; /* Tempbuff for recordpack */
+ uchar *int_keypos, /* Save position for next/previous */
*int_maxpos; /* -""- */
uint int_nod_flag; /* -""- */
uint32 int_keytree_version; /* -""- */
@@ -325,6 +326,7 @@ typedef struct st_mi_sort_param
uchar **sort_keys;
byte *rec_buff;
void *wordlist, *wordptr;
+ MEM_ROOT wordroot;
char *record;
MY_TMPDIR *tmpdir;
int (*key_cmp)(struct st_mi_sort_param *, const void *, const void *);
@@ -591,7 +593,7 @@ extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old,
extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf);
extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos,
uint length,int re_read_if_possibly);
-extern void update_auto_increment(MI_INFO *info,const byte *record);
+extern ulonglong retrieve_auto_increment(MI_INFO *info,const byte *record);
extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**);
#define mi_get_rec_buff_ptr(info,buf) \
diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c
index 5b3067cb115..556d0f46145 100644
--- a/storage/myisam/myisampack.c
+++ b/storage/myisam/myisampack.c
@@ -3033,7 +3033,7 @@ static int mrg_rrnd(PACK_MRG_INFO *info,byte *buf)
{
isam_info= *(info->current=info->file);
info->end=info->current+info->count;
- mi_extra(isam_info, HA_EXTRA_RESET, 0);
+ mi_reset(isam_info);
mi_extra(isam_info, HA_EXTRA_CACHE, 0);
filepos=isam_info->s->pack.header_length;
}
@@ -3056,7 +3056,7 @@ static int mrg_rrnd(PACK_MRG_INFO *info,byte *buf)
info->current++;
isam_info= *info->current;
filepos=isam_info->s->pack.header_length;
- mi_extra(isam_info,HA_EXTRA_RESET, 0);
+ mi_reset(isam_info);
mi_extra(isam_info,HA_EXTRA_CACHE, 0);
}
}
diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c
index c9562461f56..44e7e8b464e 100644
--- a/storage/myisam/sort.c
+++ b/storage/myisam/sort.c
@@ -447,6 +447,7 @@ err:
close_cached_file(&info->tempfile_for_exceptions);
ok:
+ free_root(&info->wordroot, MYF(0));
remove_io_thread(&info->read_cache);
pthread_mutex_lock(&info->sort_info->mutex);
info->sort_info->threads_running--;
diff --git a/storage/myisammrg/myrg_extra.c b/storage/myisammrg/myrg_extra.c
index 62cf5f01aba..ef7eeb9d4d9 100644
--- a/storage/myisammrg/myrg_extra.c
+++ b/storage/myisammrg/myrg_extra.c
@@ -38,10 +38,10 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function,
}
else
{
- if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET ||
- function == HA_EXTRA_PREPARE_FOR_UPDATE)
+ if (function == HA_EXTRA_NO_CACHE ||
+ function == HA_EXTRA_PREPARE_FOR_UPDATE)
info->cache_in_use=0;
- if (function == HA_EXTRA_RESET || function == HA_EXTRA_RESET_STATE)
+ if (function == HA_EXTRA_RESET_STATE)
{
info->current_table=0;
info->last_used_table=info->open_tables;
@@ -66,3 +66,23 @@ void myrg_extrafunc(MYRG_INFO *info, invalidator_by_filename inv)
DBUG_VOID_RETURN;
}
+
+
+int myrg_reset(MYRG_INFO *info)
+{
+ int save_error= 0;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_reset");
+
+ info->cache_in_use=0;
+ info->current_table=0;
+ info->last_used_table= info->open_tables;
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ {
+ int error;
+ if ((error= mi_reset(file->table)))
+ save_error=error;
+ }
+ DBUG_RETURN(save_error);
+}
diff --git a/storage/ndb/include/mgmapi/mgmapi.h b/storage/ndb/include/mgmapi/mgmapi.h
index 4585e78029a..5a0ffcfe2c6 100644
--- a/storage/ndb/include/mgmapi/mgmapi.h
+++ b/storage/ndb/include/mgmapi/mgmapi.h
@@ -849,16 +849,6 @@ extern "C" {
enum ndb_mgm_event_category category,
int level,
struct ndb_mgm_reply* reply);
-
- /**
- * Returns the port number where statistics information is sent
- *
- * @param handle NDB management handle.
- * @param reply Reply message.
- * @return -1 on error.
- */
- int ndb_mgm_get_stat_port(NdbMgmHandle handle,
- struct ndb_mgm_reply* reply);
#endif
/**
diff --git a/storage/ndb/include/ndbapi/Ndb.hpp b/storage/ndb/include/ndbapi/Ndb.hpp
index 010b85b03a9..dcd03cdc467 100644
--- a/storage/ndb/include/ndbapi/Ndb.hpp
+++ b/storage/ndb/include/ndbapi/Ndb.hpp
@@ -986,6 +986,7 @@ class NdbBlob;
class NdbReceiver;
class TransporterFacade;
class PollGuard;
+class Ndb_local_table_info;
template <class T> struct Ndb_free_list_t;
typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
@@ -1001,6 +1002,9 @@ typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
#define WAITFOR_RESPONSE_TIMEOUT 120000 // Milliseconds
#endif
+#define NDB_SYSTEM_DATABASE "sys"
+#define NDB_SYSTEM_SCHEMA "def"
+
/**
* @class Ndb
* @brief Represents the NDB kernel and is the main class of the NDB API.
@@ -1262,6 +1266,7 @@ public:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ int flushIncompleteEvents(Uint64 gci);
NdbEventOperation *getEventOperation(NdbEventOperation* eventOp= 0);
Uint64 getLatestGCI();
void forceGCP();
@@ -1462,35 +1467,59 @@ public:
/**
* Return a unique tuple id for a table. The id sequence is
- * ascending but may contain gaps.
+ * ascending but may contain gaps. Methods which have no
+ * TupleIdRange argument use NDB API dict cache. They may
+ * not be called from mysqld.
*
* @param aTableName table name
*
* @param cacheSize number of values to cache in this Ndb object
*
- * @return tuple id or 0 on error
+ * @return 0 or -1 on error, and tupleId in out parameter
*/
+ struct TupleIdRange {
+ TupleIdRange() {}
+ Uint64 m_first_tuple_id;
+ Uint64 m_last_tuple_id;
+ void reset() {
+ m_first_tuple_id = ~(Uint64)0;
+ m_last_tuple_id = ~(Uint64)0;
+ };
+ };
+
int initAutoIncrement();
- Uint64 getAutoIncrementValue(const char* aTableName,
- Uint32 cacheSize = 1);
- Uint64 getAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint32 cacheSize = 1);
- Uint64 readAutoIncrementValue(const char* aTableName);
- Uint64 readAutoIncrementValue(const NdbDictionary::Table * aTable);
- bool setAutoIncrementValue(const char* aTableName, Uint64 val,
- bool increase = false);
- bool setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val,
- bool increase = false);
- Uint64 getTupleIdFromNdb(const char* aTableName,
- Uint32 cacheSize = 1000);
- Uint64 getTupleIdFromNdb(Uint32 aTableId,
- Uint32 cacheSize = 1000);
- Uint64 readTupleIdFromNdb(Uint32 aTableId);
- bool setTupleIdInNdb(const char* aTableName, Uint64 val,
- bool increase);
- bool setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase);
- Uint64 opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op);
+ int getAutoIncrementValue(const char* aTableName,
+ Uint64 & tupleId, Uint32 cacheSize);
+ int getAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 & tupleId, Uint32 cacheSize);
+ int getAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 & tupleId,
+ Uint32 cacheSize);
+ int readAutoIncrementValue(const char* aTableName,
+ Uint64 & tupleId);
+ int readAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 & tupleId);
+ int readAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 & tupleId);
+ int setAutoIncrementValue(const char* aTableName,
+ Uint64 tupleId, bool increase);
+ int setAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 tupleId, bool increase);
+ int setAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 tupleId,
+ bool increase);
+private:
+ int getTupleIdFromNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & tupleId,
+ Uint32 cacheSize);
+ int readTupleIdFromNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & tupleId);
+ int setTupleIdInNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 tupleId, bool increase);
+ int opTupleIdOnNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & opValue, Uint32 op);
+public:
/**
*/
@@ -1647,6 +1676,8 @@ private:
const char * externalizeIndexName(const char * internalIndexName,
bool fullyQualifiedNames);
const char * externalizeIndexName(const char * internalIndexName);
+ const BaseString old_internalize_index_name(const NdbTableImpl * table,
+ const char * external_name) const;
const BaseString internalize_index_name(const NdbTableImpl * table,
const char * external_name) const;
@@ -1693,12 +1724,8 @@ private:
Uint64 the_last_check_time;
Uint64 theFirstTransId;
-
- // The tupleId is retreived from DB the
- // tupleId is unique for each tableid.
+ // The tupleId is retrieved from DB
const NdbDictionary::Table *m_sys_tab_0;
- Uint64 theFirstTupleId[2048];
- Uint64 theLastTupleId[2048];
Uint32 theRestartGCI; // the Restart GCI used by DIHNDBTAMPER
diff --git a/storage/ndb/include/ndbapi/NdbDictionary.hpp b/storage/ndb/include/ndbapi/NdbDictionary.hpp
index b31e2551e89..27e0aede36d 100644
--- a/storage/ndb/include/ndbapi/NdbDictionary.hpp
+++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp
@@ -1132,7 +1132,8 @@ public:
_TE_NODE_FAILURE=10,
_TE_SUBSCRIBE=11,
_TE_UNSUBSCRIBE=12,
- _TE_NUL=13 // internal (e.g. INS o DEL within same GCI)
+ _TE_NUL=13, // internal (e.g. INS o DEL within same GCI)
+ _TE_ACTIVE=14 // internal (node becomes active)
};
#endif
/**
@@ -1634,6 +1635,16 @@ public:
int listIndexes(List & list, const char * tableName);
int listIndexes(List & list, const char * tableName) const;
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /**
+ * Fetch list of indexes of given table.
+ * @param list Reference to list where to store the listed indexes
+ * @param table Reference to table that index belongs to.
+ * @return 0 if successful, otherwise -1
+ */
+ int listIndexes(List & list, const Table &table) const;
+#endif
+
/** @} *******************************************************************/
/**
* @name Events
diff --git a/storage/ndb/include/util/SocketServer.hpp b/storage/ndb/include/util/SocketServer.hpp
index e766a0b99c4..c4f7e8c0ade 100644
--- a/storage/ndb/include/util/SocketServer.hpp
+++ b/storage/ndb/include/util/SocketServer.hpp
@@ -106,7 +106,8 @@ public:
void stopSessions(bool wait = false);
void foreachSession(void (*f)(Session*, void*), void *data);
-
+ void checkSessions();
+
private:
struct SessionInstance {
Service * m_service;
@@ -117,12 +118,13 @@ private:
Service * m_service;
NDB_SOCKET_TYPE m_socket;
};
- MutexVector<SessionInstance> m_sessions;
+ NdbLockable m_session_mutex;
+ Vector<SessionInstance> m_sessions;
MutexVector<ServiceInstance> m_services;
unsigned m_maxSessions;
void doAccept();
- void checkSessions();
+ void checkSessionsImpl();
void startSession(SessionInstance &);
/**
diff --git a/storage/ndb/src/common/util/SocketServer.cpp b/storage/ndb/src/common/util/SocketServer.cpp
index f0af925cf6d..f9d2c7463be 100644
--- a/storage/ndb/src/common/util/SocketServer.cpp
+++ b/storage/ndb/src/common/util/SocketServer.cpp
@@ -184,9 +184,12 @@ SocketServer::doAccept(){
SessionInstance s;
s.m_service = si.m_service;
s.m_session = si.m_service->newSession(childSock);
- if(s.m_session != 0){
+ if(s.m_session != 0)
+ {
+ m_session_mutex.lock();
m_sessions.push_back(s);
startSession(m_sessions.back());
+ m_session_mutex.unlock();
}
continue;
@@ -240,10 +243,13 @@ void
SocketServer::doRun(){
while(!m_stopThread){
- checkSessions();
+ m_session_mutex.lock();
+ checkSessionsImpl();
if(m_sessions.size() < m_maxSessions){
+ m_session_mutex.unlock();
doAccept();
} else {
+ m_session_mutex.unlock();
NdbSleep_MilliSleep(200);
}
}
@@ -276,17 +282,30 @@ transfer(NDB_SOCKET_TYPE sock){
void
SocketServer::foreachSession(void (*func)(SocketServer::Session*, void *), void *data)
{
+ m_session_mutex.lock();
for(int i = m_sessions.size() - 1; i >= 0; i--){
(*func)(m_sessions[i].m_session, data);
}
- checkSessions();
+ m_session_mutex.unlock();
}
void
-SocketServer::checkSessions(){
- for(int i = m_sessions.size() - 1; i >= 0; i--){
- if(m_sessions[i].m_session->m_stopped){
- if(m_sessions[i].m_thread != 0){
+SocketServer::checkSessions()
+{
+ m_session_mutex.lock();
+ checkSessionsImpl();
+ m_session_mutex.unlock();
+}
+
+void
+SocketServer::checkSessionsImpl()
+{
+ for(int i = m_sessions.size() - 1; i >= 0; i--)
+ {
+ if(m_sessions[i].m_session->m_stopped)
+ {
+ if(m_sessions[i].m_thread != 0)
+ {
void* ret;
NdbThread_WaitFor(m_sessions[i].m_thread, &ret);
NdbThread_Destroy(&m_sessions[i].m_thread);
@@ -301,19 +320,26 @@ SocketServer::checkSessions(){
void
SocketServer::stopSessions(bool wait){
int i;
+ m_session_mutex.lock();
for(i = m_sessions.size() - 1; i>=0; i--)
{
m_sessions[i].m_session->stopSession();
m_sessions[i].m_session->m_stop = true; // to make sure
}
+ m_session_mutex.unlock();
+
for(i = m_services.size() - 1; i>=0; i--)
m_services[i].m_service->stopSessions();
if(wait){
+ m_session_mutex.lock();
while(m_sessions.size() > 0){
- checkSessions();
+ checkSessionsImpl();
+ m_session_mutex.unlock();
NdbSleep_MilliSleep(100);
+ m_session_mutex.lock();
}
+ m_session_mutex.unlock();
}
}
@@ -348,4 +374,4 @@ sessionThread_C(void* _sc){
}
template class MutexVector<SocketServer::ServiceInstance>;
-template class MutexVector<SocketServer::SessionInstance>;
+template class Vector<SocketServer::SessionInstance>;
diff --git a/storage/ndb/src/common/util/socket_io.cpp b/storage/ndb/src/common/util/socket_io.cpp
index 83a546de773..58636e6663d 100644
--- a/storage/ndb/src/common/util/socket_io.cpp
+++ b/storage/ndb/src/common/util/socket_io.cpp
@@ -48,58 +48,66 @@ read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
extern "C"
int
-readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
char * buf, int buflen){
if(buflen <= 1)
return 0;
+ int sock_flags= fcntl(socket, F_GETFL);
+ if(fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1)
+ return -1;
+
fd_set readset;
FD_ZERO(&readset);
FD_SET(socket, &readset);
-
+
struct timeval timeout;
timeout.tv_sec = (timeout_millis / 1000);
timeout.tv_usec = (timeout_millis % 1000) * 1000;
const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
- if(selectRes == 0)
+ if(selectRes == 0){
return 0;
-
+ }
+
if(selectRes == -1){
+ fcntl(socket, F_SETFL, sock_flags);
return -1;
}
-
- int pos = 0; buf[pos] = 0;
- while(true){
- const int t = recv(socket, &buf[pos], 1, 0);
- if(t != 1){
- return -1;
- }
- if(buf[pos] == '\n'){
- buf[pos] = 0;
- if(pos > 0 && buf[pos-1] == '\r'){
- pos--;
- buf[pos] = 0;
+ buf[0] = 0;
+ const int t = recv(socket, buf, buflen, MSG_PEEK);
+
+ if(t < 1)
+ {
+ fcntl(socket, F_SETFL, sock_flags);
+ return -1;
+ }
+
+ for(int i=0; i< t;i++)
+ {
+ if(buf[i] == '\n'){
+ recv(socket, buf, i+1, 0);
+ buf[i] = 0;
+
+ if(i > 0 && buf[i-1] == '\r'){
+ i--;
+ buf[i] = 0;
}
- return pos;
- }
- pos++;
- if(pos == (buflen - 1)){
- buf[pos] = 0;
- return buflen;
- }
-
- FD_ZERO(&readset);
- FD_SET(socket, &readset);
- timeout.tv_sec = (timeout_millis / 1000);
- timeout.tv_usec = (timeout_millis % 1000) * 1000;
- const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
- if(selectRes != 1){
- return -1;
+ fcntl(socket, F_SETFL, sock_flags);
+ return t;
}
}
+
+ if(t == (buflen - 1)){
+ recv(socket, buf, t, 0);
+ buf[t] = 0;
+ fcntl(socket, F_SETFL, sock_flags);
+ return buflen;
+ }
+
+ return 0;
}
extern "C"
diff --git a/storage/ndb/src/kernel/blocks/ERROR_codes.txt b/storage/ndb/src/kernel/blocks/ERROR_codes.txt
index 059c80a960d..d69faa90f72 100644
--- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt
+++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt
@@ -63,6 +63,9 @@ Delay GCP_SAVEREQ by 10 secs
7165: Delay INCL_NODE_REQ in starting node yeilding error in GCP_PREPARE
+7030: Delay in GCP_PREPARE until node has completed a node failure
+7031: Delay in GCP_PREPARE and die 3s later
+
ERROR CODES FOR TESTING NODE FAILURE, LOCAL CHECKPOINT HANDLING:
-----------------------------------------------------------------
diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index 9936217bbf3..bb4c2ed197e 100644
--- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -5601,6 +5601,12 @@ Dbdih::checkLocalNodefailComplete(Signal* signal, Uint32 failedNodeId,
return;
}
+ if (ERROR_INSERTED(7030))
+ {
+ ndbout_c("Reenable GCP_PREPARE");
+ CLEAR_ERROR_INSERT_VALUE;
+ }
+
NFCompleteRep * const nf = (NFCompleteRep *)&signal->theData[0];
nf->blockNo = DBDIH;
nf->nodeId = cownNodeId;
@@ -7733,6 +7739,16 @@ void Dbdih::execGCP_PREPARE(Signal* signal)
{
jamEntry();
CRASH_INSERTION(7005);
+
+ if (ERROR_INSERTED(7030))
+ {
+ cgckptflag = true;
+ ndbout_c("Delayed GCP_PREPARE 5s");
+ sendSignalWithDelay(reference(), GSN_GCP_PREPARE, signal, 5000,
+ signal->getLength());
+ return;
+ }
+
Uint32 masterNodeId = signal->theData[0];
Uint32 gci = signal->theData[1];
BlockReference retRef = calcDihBlockRef(masterNodeId);
@@ -7745,6 +7761,14 @@ void Dbdih::execGCP_PREPARE(Signal* signal)
cgcpParticipantState = GCP_PARTICIPANT_PREPARE_RECEIVED;
cnewgcp = gci;
+ if (ERROR_INSERTED(7031))
+ {
+ ndbout_c("Crashing delayed in GCP_PREPARE 3s");
+ signal->theData[0] = 9999;
+ sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 3000, 1);
+ return;
+ }
+
signal->theData[0] = cownNodeId;
signal->theData[1] = gci;
sendSignal(retRef, GSN_GCP_PREPARECONF, signal, 2, JBA);
diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index 0989807db4a..869ae116f43 100644
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -7076,18 +7076,20 @@ Dbtc::nodeFailCheckTransactions(Signal* signal,
{
jam();
Ptr<ApiConnectRecord> transPtr;
+ Uint32 TtcTimer = ctcTimer;
+ Uint32 TapplTimeout = c_appl_timeout_value;
for (transPtr.i = transPtrI; transPtr.i < capiConnectFilesize; transPtr.i++)
{
ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
if (transPtr.p->m_transaction_nodes.get(failedNodeId))
{
jam();
+
// Force timeout regardless of state
- Uint32 save = c_appl_timeout_value;
c_appl_timeout_value = 1;
- setApiConTimer(transPtr.i, 0, __LINE__);
+ setApiConTimer(transPtr.i, TtcTimer - 2, __LINE__);
timeOutFoundLab(signal, transPtr.i, ZNODEFAIL_BEFORE_COMMIT);
- c_appl_timeout_value = save;
+ c_appl_timeout_value = TapplTimeout;
}
// Send CONTINUEB to continue later
diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
index 90abe2cb809..1b6fef9de37 100644
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
@@ -1926,6 +1926,7 @@ int Dbtup::interpreterNextLab(Signal* signal,
// word read. Thus we set the register to be a 32 bit register.
/* ------------------------------------------------------------- */
TregMemBuffer[theRegister]= 0x50;
+ // arithmetic conversion if big-endian
* (Int64*)(TregMemBuffer+theRegister+2)=
TregMemBuffer[theRegister+1];
} else if (TnoDataRW == 3) {
@@ -1985,6 +1986,11 @@ int Dbtup::interpreterNextLab(Signal* signal,
Tlen= TattrNoOfWords + 1;
if (Toptype == ZUPDATE) {
if (TattrNoOfWords <= 2) {
+ if (TattrNoOfWords == 1) {
+ // arithmetic conversion if big-endian
+ TdataForUpdate[1] = *(Int64*)&TregMemBuffer[theRegister + 2];
+ TdataForUpdate[2] = 0;
+ }
if (TregType == 0) {
/* --------------------------------------------------------- */
// Write a NULL value into the attribute
diff --git a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
index b0372ec89a2..7c48ebb5e8b 100644
--- a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
+++ b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
@@ -1645,10 +1645,9 @@ void Ndbcntr::systemErrorLab(Signal* signal, int line)
/* |-2048| # 1 00000001 | */
/* | : | : | */
/* | -1 | # 1 00000001 | */
-/* | 0 | 0 | */
-/* | 1 | 0 | */
-/* | : | : | */
-/* | 2047| 0 | */
+/* | 1 | 0 | tupleid sequence now created on first use */
+/* | : | : | v */
+/* | 2048| 0 | v */
/*---------------------------------------------------------------------------*/
void Ndbcntr::createSystableLab(Signal* signal, unsigned index)
{
@@ -1859,8 +1858,7 @@ void Ndbcntr::crSystab8Lab(Signal* signal)
jam();
ckey = 1;
ctransidPhase = ZFALSE;
- crSystab7Lab(signal);
- return;
+ // skip 2nd loop - tupleid sequence now created on first use
}//if
signal->theData[0] = ctcConnectionP;
signal->theData[1] = reference();
diff --git a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index 8772e00f027..4d5ac377a5a 100644
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -827,7 +827,7 @@ void Qmgr::execCM_REGCONF(Signal* signal)
ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
ndbrequire(c_start.m_gsn == GSN_CM_REGREQ);
- ndbrequire(myNodePtr.p->phase = ZSTARTING);
+ ndbrequire(myNodePtr.p->phase == ZSTARTING);
cpdistref = cmRegConf->presidentBlockRef;
cpresident = cmRegConf->presidentNodeId;
diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp
index 867b13e1e40..91f0fab06f8 100644
--- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp
+++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp
@@ -2649,6 +2649,22 @@ Suma::reportAllSubscribers(Signal *signal,
SubscriptionPtr subPtr,
SubscriberPtr subbPtr)
{
+ SubTableData * data = (SubTableData*)signal->getDataPtrSend();
+
+ if (table_event == NdbDictionary::Event::_TE_SUBSCRIBE)
+ {
+ data->gci = m_last_complete_gci + 1;
+ data->tableId = subPtr.p->m_tableId;
+ data->operation = NdbDictionary::Event::_TE_ACTIVE;
+ data->ndbd_nodeid = refToNode(reference());
+ data->changeMask = 0;
+ data->totalLen = 0;
+ data->req_nodeid = refToNode(subbPtr.p->m_senderRef);
+ data->senderData = subbPtr.p->m_senderData;
+ sendSignal(subbPtr.p->m_senderRef, GSN_SUB_TABLE_DATA, signal,
+ SubTableData::SignalLength, JBB);
+ }
+
if (!(subPtr.p->m_options & Subscription::REPORT_SUBSCRIBE))
{
return;
@@ -2663,7 +2679,6 @@ Suma::reportAllSubscribers(Signal *signal,
ndbout_c("reportAllSubscribers subPtr.i: %d subPtr.p->n_subscribers: %d",
subPtr.i, subPtr.p->n_subscribers);
//#endif
- SubTableData * data = (SubTableData*)signal->getDataPtrSend();
data->gci = m_last_complete_gci + 1;
data->tableId = subPtr.p->m_tableId;
data->operation = table_event;
diff --git a/storage/ndb/src/kernel/vm/Configuration.cpp b/storage/ndb/src/kernel/vm/Configuration.cpp
index e0e414e5669..12badffe0e0 100644
--- a/storage/ndb/src/kernel/vm/Configuration.cpp
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp
@@ -49,7 +49,9 @@ extern EventLogger g_eventLogger;
enum ndbd_options {
OPT_INITIAL = NDB_STD_OPTIONS_LAST,
OPT_NODAEMON,
- OPT_FOREGROUND
+ OPT_FOREGROUND,
+ OPT_NOWAIT_NODES,
+ OPT_INITIAL_START
};
NDB_STD_OPTS_VARS;
@@ -88,11 +90,11 @@ static struct my_option my_long_options[] =
" (implies --nodaemon)",
(gptr*) &_foreground, (gptr*) &_foreground, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
- { "nowait-nodes", NO_ARG,
+ { "nowait-nodes", OPT_NOWAIT_NODES,
"Nodes that will not be waited for during start",
(gptr*) &_nowait_nodes, (gptr*) &_nowait_nodes, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- { "initial-start", NO_ARG,
+ { "initial-start", OPT_INITIAL_START,
"Perform initial start",
(gptr*) &_initialstart, (gptr*) &_initialstart, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
diff --git a/storage/ndb/src/mgmapi/mgmapi.cpp b/storage/ndb/src/mgmapi/mgmapi.cpp
index b3d2d403dcc..6dfb48667aa 100644
--- a/storage/ndb/src/mgmapi/mgmapi.cpp
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp
@@ -1308,33 +1308,6 @@ ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
extern "C"
int
-ndb_mgm_get_stat_port(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
-{
- SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_stat_port");
- const ParserRow<ParserDummy> stat_reply[] = {
- MGM_CMD("error", NULL, ""),
- MGM_ARG("result", String, Mandatory, "Error message"),
- MGM_CMD("get statport reply", NULL, ""),
- MGM_ARG("tcpport", Int, Mandatory, "TCP port for statistics"),
- MGM_END()
- };
- CHECK_HANDLE(handle, -1);
- CHECK_CONNECTED(handle, -1);
-
- Properties args;
- const Properties *reply;
- reply = ndb_mgm_call(handle, stat_reply, "get statport", &args);
- CHECK_REPLY(reply, -1);
-
- Uint32 port;
- reply->get("tcpport", &port);
-
- delete reply;
- return port;
-}
-
-extern "C"
-int
ndb_mgm_dump_state(NdbMgmHandle handle, int nodeId, int* _args,
int _num_args, struct ndb_mgm_reply* /* reply */)
{
diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp
index be15484688b..2731bfd422b 100644
--- a/storage/ndb/src/mgmsrv/Services.cpp
+++ b/storage/ndb/src/mgmsrv/Services.cpp
@@ -121,8 +121,6 @@ static const unsigned int MAX_WRITE_TIMEOUT = 100 ;
const
ParserRow<MgmApiSession> commands[] = {
- MGM_CMD("get statport", &MgmApiSession::getStatPort, ""),
-
MGM_CMD("get config", &MgmApiSession::getConfig, ""),
MGM_ARG("version", Int, Mandatory, "Configuration version number"),
MGM_ARG("node", Int, Optional, "Node ID"),
@@ -502,6 +500,7 @@ MgmApiSession::get_nodeid(Parser_t::Context &,
ps.tick= tick;
m_mgmsrv.get_socket_server()->
foreachSession(stop_session_if_timed_out,&ps);
+ m_mgmsrv.get_socket_server()->checkSessions();
error_string = "";
continue;
}
@@ -649,15 +648,6 @@ MgmApiSession::getConfig_common(Parser_t::Context &,
}
void
-MgmApiSession::getStatPort(Parser_t::Context &,
- const class Properties &) {
-
- m_output->println("get statport reply");
- m_output->println("tcpport: %d", 0);
- m_output->println("");
-}
-
-void
MgmApiSession::insertError(Parser<MgmApiSession>::Context &,
Properties const &args) {
Uint32 node = 0, error = 0;
@@ -1559,6 +1549,7 @@ MgmApiSession::purge_stale_sessions(Parser_t::Context &ctx,
ps.free_nodes.bitXORC(NodeBitmask()); // invert connected_nodes to get free nodes
m_mgmsrv.get_socket_server()->foreachSession(stop_session_if_not_connected,&ps);
+ m_mgmsrv.get_socket_server()->checkSessions();
m_output->println("purge stale sessions reply");
if (str.length() > 0)
diff --git a/storage/ndb/src/mgmsrv/Services.hpp b/storage/ndb/src/mgmsrv/Services.hpp
index 975202b96df..abe0233cb33 100644
--- a/storage/ndb/src/mgmsrv/Services.hpp
+++ b/storage/ndb/src/mgmsrv/Services.hpp
@@ -53,7 +53,6 @@ public:
virtual ~MgmApiSession();
void runSession();
- void getStatPort(Parser_t::Context &ctx, const class Properties &args);
void getConfig(Parser_t::Context &ctx, const class Properties &args);
#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
void getConfig_old(Parser_t::Context &ctx);
diff --git a/storage/ndb/src/ndbapi/DictCache.cpp b/storage/ndb/src/ndbapi/DictCache.cpp
index ea8a08c4065..8a0bf2f8e8b 100644
--- a/storage/ndb/src/ndbapi/DictCache.cpp
+++ b/storage/ndb/src/ndbapi/DictCache.cpp
@@ -47,6 +47,7 @@ Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl)
{
assert(! is_ndb_blob_table(table_impl));
m_table_impl= table_impl;
+ m_tuple_id_range.reset();
}
Ndb_local_table_info::~Ndb_local_table_info()
diff --git a/storage/ndb/src/ndbapi/DictCache.hpp b/storage/ndb/src/ndbapi/DictCache.hpp
index 77344586669..e909590e03e 100644
--- a/storage/ndb/src/ndbapi/DictCache.hpp
+++ b/storage/ndb/src/ndbapi/DictCache.hpp
@@ -33,6 +33,10 @@ public:
static Ndb_local_table_info *create(NdbTableImpl *table_impl, Uint32 sz=0);
static void destroy(Ndb_local_table_info *);
NdbTableImpl *m_table_impl;
+
+ // range of cached tuple ids per thread
+ Ndb::TupleIdRange m_tuple_id_range;
+
Uint64 m_local_data[1]; // Must be last member. Used to access extra space.
private:
Ndb_local_table_info(NdbTableImpl *table_impl);
diff --git a/storage/ndb/src/ndbapi/Ndb.cpp b/storage/ndb/src/ndbapi/Ndb.cpp
index 5cc4875d78f..5b0a9e9d330 100644
--- a/storage/ndb/src/ndbapi/Ndb.cpp
+++ b/storage/ndb/src/ndbapi/Ndb.cpp
@@ -747,158 +747,271 @@ Remark: Returns a new TupleId to the application.
The TupleId comes from SYSTAB_0 where SYSKEY_0 = TableId.
It is initialized to (TableId << 48) + 1 in NdbcntrMain.cpp.
****************************************************************************/
-Uint64
-Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize)
+int
+Ndb::getAutoIncrementValue(const char* aTableName,
+ Uint64 & tupleId, Uint32 cacheSize)
{
- DBUG_ENTER("getAutoIncrementValue");
+ DBUG_ENTER("Ndb::getAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
BaseString internal_tabname(internalize_table_name(aTableName));
Ndb_local_table_info *info=
theDictionary->get_local_table_info(internal_tabname);
- if (info == 0)
- DBUG_RETURN(~(Uint64)0);
- const NdbTableImpl *table= info->m_table_impl;
- Uint64 tupleId = getTupleIdFromNdb(table->m_id, cacheSize);
- DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
- DBUG_RETURN(tupleId);
+ if (info == 0) {
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
+ }
+ const NdbTableImpl* table = info->m_table_impl;
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize)
+int
+Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 & tupleId, Uint32 cacheSize)
{
- DBUG_ENTER("getAutoIncrementValue");
- if (aTable == 0)
- DBUG_RETURN(~(Uint64)0);
+ DBUG_ENTER("Ndb::getAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
+ assert(aTable != 0);
const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
- Uint64 tupleId = getTupleIdFromNdb(table->m_id, cacheSize);
- DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
- DBUG_RETURN(tupleId);
+ const BaseString& internal_tabname = table->m_internalName;
+
+ Ndb_local_table_info *info=
+ theDictionary->get_local_table_info(internal_tabname);
+ if (info == 0) {
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
+ }
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::getTupleIdFromNdb(const char* aTableName, Uint32 cacheSize)
+int
+Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 & tupleId,
+ Uint32 cacheSize)
{
- const NdbTableImpl* table = theDictionary->getTable(aTableName);
- if (table == 0)
- return ~(Uint64)0;
- return getTupleIdFromNdb(table->m_id, cacheSize);
+ DBUG_ENTER("Ndb::getAutoIncrementValue");
+ assert(aTable != 0);
+ const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
+
+ if (getTupleIdFromNdb(table, range, tupleId, cacheSize) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize)
+int
+Ndb::getTupleIdFromNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & tupleId, Uint32 cacheSize)
{
- DBUG_ENTER("getTupleIdFromNdb");
- if ( theFirstTupleId[aTableId] != theLastTupleId[aTableId] )
+ DBUG_ENTER("Ndb::getTupleIdFromNdb");
+ if (range.m_first_tuple_id != range.m_last_tuple_id)
{
- theFirstTupleId[aTableId]++;
- DBUG_PRINT("info", ("next cached value %ul",
- (ulong) theFirstTupleId[aTableId]));
- DBUG_RETURN(theFirstTupleId[aTableId]);
+ assert(range.m_first_tuple_id < range.m_last_tuple_id);
+ tupleId = ++range.m_first_tuple_id;
+ DBUG_PRINT("info", ("next cached value %llu", (ulonglong)tupleId));
}
- else // theFirstTupleId == theLastTupleId
+ else
{
- DBUG_PRINT("info",("reading %u values from database",
- (cacheSize == 0) ? 1 : cacheSize));
- DBUG_RETURN(opTupleIdOnNdb(aTableId, (cacheSize == 0) ? 1 : cacheSize, 0));
+ if (cacheSize == 0)
+ cacheSize = 1;
+ DBUG_PRINT("info", ("reading %u values from database", (uint)cacheSize));
+ /*
+ * reserve next cacheSize entries in db. adds cacheSize to NEXTID
+ * and returns first tupleId in the new range.
+ */
+ Uint64 opValue = cacheSize;
+ if (opTupleIdOnNdb(table, range, opValue, 0) == -1)
+ DBUG_RETURN(-1);
+ tupleId = opValue;
}
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::readAutoIncrementValue(const char* aTableName)
+int
+Ndb::readAutoIncrementValue(const char* aTableName,
+ Uint64 & tupleId)
{
- DBUG_ENTER("readAutoIncrementValue");
- const NdbTableImpl* table = theDictionary->getTable(aTableName);
- if (table == 0) {
- theError= theDictionary->getNdbError();
- DBUG_RETURN(~(Uint64)0);
+ DBUG_ENTER("Ndb::readAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
+ BaseString internal_tabname(internalize_table_name(aTableName));
+
+ Ndb_local_table_info *info=
+ theDictionary->get_local_table_info(internal_tabname);
+ if (info == 0) {
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
}
- Uint64 tupleId = readTupleIdFromNdb(table->m_id);
- DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
- DBUG_RETURN(tupleId);
+ const NdbTableImpl* table = info->m_table_impl;
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (readTupleIdFromNdb(table, range, tupleId) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable)
+int
+Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 & tupleId)
{
- DBUG_ENTER("readAutoIncrementValue");
- if (aTable == 0)
- DBUG_RETURN(~(Uint64)0);
+ DBUG_ENTER("Ndb::readAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
+ assert(aTable != 0);
const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
- Uint64 tupleId = readTupleIdFromNdb(table->m_id);
- DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
- DBUG_RETURN(tupleId);
+ const BaseString& internal_tabname = table->m_internalName;
+
+ Ndb_local_table_info *info=
+ theDictionary->get_local_table_info(internal_tabname);
+ if (info == 0) {
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
+ }
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (readTupleIdFromNdb(table, range, tupleId) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-Uint64
-Ndb::readTupleIdFromNdb(Uint32 aTableId)
+int
+Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 & tupleId)
{
- if ( theFirstTupleId[aTableId] == theLastTupleId[aTableId] )
- // Cache is empty, check next in database
- return opTupleIdOnNdb(aTableId, 0, 3);
+ DBUG_ENTER("Ndb::readAutoIncrementValue");
+ assert(aTable != 0);
+ const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
- return theFirstTupleId[aTableId] + 1;
+ if (readTupleIdFromNdb(table, range, tupleId) == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
-bool
-Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase)
+int
+Ndb::readTupleIdFromNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & tupleId)
{
- DBUG_ENTER("setAutoIncrementValue");
+ DBUG_ENTER("Ndb::readTupleIdFromNdb");
+ if (range.m_first_tuple_id != range.m_last_tuple_id)
+ {
+ assert(range.m_first_tuple_id < range.m_last_tuple_id);
+ tupleId = range.m_first_tuple_id + 1;
+ }
+ else
+ {
+ /*
+ * peek at NEXTID. does not reserve it so the value is valid
+ * only if no other transactions are allowed.
+ */
+ Uint64 opValue = 0;
+ if (opTupleIdOnNdb(table, range, opValue, 3) == -1)
+ DBUG_RETURN(-1);
+ tupleId = opValue;
+ }
+ DBUG_RETURN(0);
+}
+
+int
+Ndb::setAutoIncrementValue(const char* aTableName,
+ Uint64 tupleId, bool increase)
+{
+ DBUG_ENTER("Ndb::setAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
BaseString internal_tabname(internalize_table_name(aTableName));
Ndb_local_table_info *info=
theDictionary->get_local_table_info(internal_tabname);
if (info == 0) {
- theError= theDictionary->getNdbError();
- DBUG_RETURN(false);
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
}
- const NdbTableImpl* table= info->m_table_impl;
- DBUG_RETURN(setTupleIdInNdb(table->m_id, val, increase));
+ const NdbTableImpl* table = info->m_table_impl;
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (setTupleIdInNdb(table, range, tupleId, increase) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
}
-bool
-Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase)
+int
+Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable,
+ Uint64 tupleId, bool increase)
{
- DBUG_ENTER("setAutoIncrementValue");
- if (aTable == 0)
- DBUG_RETURN(~(Uint64)0);
+ DBUG_ENTER("Ndb::setAutoIncrementValue");
+ ASSERT_NOT_MYSQLD;
+ assert(aTable != 0);
const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
- DBUG_RETURN(setTupleIdInNdb(table->m_id, val, increase));
+ const BaseString& internal_tabname = table->m_internalName;
+
+ Ndb_local_table_info *info=
+ theDictionary->get_local_table_info(internal_tabname);
+ if (info == 0) {
+ theError.code = theDictionary->getNdbError().code;
+ DBUG_RETURN(-1);
+ }
+ TupleIdRange & range = info->m_tuple_id_range;
+ if (setTupleIdInNdb(table, range, tupleId, increase) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
}
-bool
-Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase )
+int
+Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable,
+ TupleIdRange & range, Uint64 tupleId,
+ bool increase)
{
- DBUG_ENTER("setTupleIdInNdb(const char*, ...)");
- const NdbTableImpl* table = theDictionary->getTable(aTableName);
- if (table == 0) {
- theError= theDictionary->getNdbError();
- DBUG_RETURN(false);
- }
- DBUG_RETURN(setTupleIdInNdb(table->m_id, val, increase));
+ DBUG_ENTER("Ndb::setAutoIncrementValue");
+ assert(aTable != 0);
+ const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
+
+ if (setTupleIdInNdb(table, range, tupleId, increase) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
}
-bool
-Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase )
+int
+Ndb::setTupleIdInNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 tupleId, bool increase)
{
- DBUG_ENTER("setTupleIdInNdb(Uint32, ...)");
+ DBUG_ENTER("Ndb::setTupleIdInNdb");
if (increase)
{
- if (theFirstTupleId[aTableId] != theLastTupleId[aTableId])
+ if (range.m_first_tuple_id != range.m_last_tuple_id)
{
- // We have a cache sequence
- if (val <= theFirstTupleId[aTableId]+1)
- DBUG_RETURN(false);
- if (val <= theLastTupleId[aTableId])
+ assert(range.m_first_tuple_id < range.m_last_tuple_id);
+ if (tupleId <= range.m_first_tuple_id + 1)
+ DBUG_RETURN(0);
+ if (tupleId <= range.m_last_tuple_id)
{
- theFirstTupleId[aTableId] = val - 1;
- DBUG_RETURN(true);
+ range.m_first_tuple_id = tupleId - 1;
+ DBUG_PRINT("info",
+ ("Setting next auto increment cached value to %llu",
+ (ulonglong)tupleId));
+ DBUG_RETURN(0);
}
- // else continue;
}
- DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 2) == val));
+ /*
+ * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to
+ * tupleId and set cached range to first = last = tupleId - 1.
+ */
+ if (opTupleIdOnNdb(table, range, tupleId, 2) == -1)
+ DBUG_RETURN(-1);
}
else
- DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 1) == val));
+ {
+ /*
+ * update NEXTID to given value. reset cached range.
+ */
+ if (opTupleIdOnNdb(table, range, tupleId, 1) == -1)
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
}
int Ndb::initAutoIncrement()
@@ -922,18 +1035,18 @@ int Ndb::initAutoIncrement()
return (m_sys_tab_0 == NULL);
}
-Uint64
-Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
+int
+Ndb::opTupleIdOnNdb(const NdbTableImpl* table,
+ TupleIdRange & range, Uint64 & opValue, Uint32 op)
{
DBUG_ENTER("Ndb::opTupleIdOnNdb");
+ Uint32 aTableId = table->m_id;
DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op));
NdbTransaction* tConnection;
NdbOperation* tOperation= 0; // Compiler warning if not initialized
Uint64 tValue;
NdbRecAttr* tRecAttrResult;
- int result;
- Uint64 ret;
CHECK_STATUS_MACRO_ZERO;
@@ -961,42 +1074,44 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
tValue = tRecAttrResult->u_64_value();
- theFirstTupleId[aTableId] = tValue - opValue;
- theLastTupleId[aTableId] = tValue - 1;
- ret = theFirstTupleId[aTableId];
+ range.m_first_tuple_id = tValue - opValue;
+ range.m_last_tuple_id = tValue - 1;
+ opValue = range.m_first_tuple_id; // out
break;
case 1:
- tOperation->updateTuple();
+ // create on first use
+ tOperation->writeTuple();
tOperation->equal("SYSKEY_0", aTableId );
tOperation->setValue("NEXTID", opValue);
if (tConnection->execute( Commit ) == -1 )
goto error_handler;
- theFirstTupleId[aTableId] = ~(Uint64)0;
- theLastTupleId[aTableId] = ~(Uint64)0;
- ret = opValue;
+ range.reset();
break;
case 2:
tOperation->interpretedUpdateTuple();
tOperation->equal("SYSKEY_0", aTableId );
tOperation->load_const_u64(1, opValue);
tOperation->read_attr("NEXTID", 2);
+ // compare NEXTID >= opValue
tOperation->branch_le(2, 1, 0);
tOperation->write_attr("NEXTID", 1);
tOperation->interpret_exit_ok();
tOperation->def_label(0);
tOperation->interpret_exit_nok(9999);
- if ( (result = tConnection->execute( Commit )) == -1 )
- goto error_handler;
-
- if (result == 9999)
- ret = ~(Uint64)0;
+ if (tConnection->execute( Commit ) == -1)
+ {
+ if (tConnection->theError.code != 9999)
+ goto error_handler;
+ }
else
{
- theFirstTupleId[aTableId] = theLastTupleId[aTableId] = opValue - 1;
- ret = opValue;
+ DBUG_PRINT("info",
+ ("Setting next auto increment value (db) to %llu",
+ (ulonglong)opValue));
+ range.m_first_tuple_id = range.m_last_tuple_id = opValue - 1;
}
break;
case 3:
@@ -1005,7 +1120,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
tRecAttrResult = tOperation->getValue("NEXTID");
if (tConnection->execute( Commit ) == -1 )
goto error_handler;
- ret = tRecAttrResult->u_64_value();
+ opValue = tRecAttrResult->u_64_value(); // out
break;
default:
goto error_handler;
@@ -1013,7 +1128,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
this->closeTransaction(tConnection);
- DBUG_RETURN(ret);
+ DBUG_RETURN(0);
error_handler:
theError.code = tConnection->theError.code;
@@ -1023,7 +1138,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
theError.code,
tConnection ? tConnection->theError.code : -1,
tOperation ? tOperation->theError.code : -1));
- DBUG_RETURN(~(Uint64)0);
+ DBUG_RETURN(-1);
}
Uint32
@@ -1196,6 +1311,35 @@ Ndb::internalize_table_name(const char *external_name) const
DBUG_RETURN(ret);
}
+const BaseString
+Ndb::old_internalize_index_name(const NdbTableImpl * table,
+ const char * external_name) const
+{
+ BaseString ret;
+ DBUG_ENTER("old_internalize_index_name");
+ DBUG_PRINT("enter", ("external_name: %s, table_id: %d",
+ external_name, table ? table->m_id : ~0));
+ if (!table)
+ {
+ DBUG_PRINT("error", ("!table"));
+ DBUG_RETURN(ret);
+ }
+
+ if (fullyQualifiedNames)
+ {
+ /* Internal index name format <db>/<schema>/<tabid>/<table> */
+ ret.assfmt("%s%d%c%s",
+ theImpl->m_prefix.c_str(),
+ table->m_id,
+ table_name_separator,
+ external_name);
+ }
+ else
+ ret.assign(external_name);
+
+ DBUG_PRINT("exit", ("internal_name: %s", ret.c_str()));
+ DBUG_RETURN(ret);
+}
const BaseString
Ndb::internalize_index_name(const NdbTableImpl * table,
@@ -1213,9 +1357,9 @@ Ndb::internalize_index_name(const NdbTableImpl * table,
if (fullyQualifiedNames)
{
- /* Internal index name format <db>/<schema>/<tabid>/<table> */
+ /* Internal index name format sys/def/<tabid>/<table> */
ret.assfmt("%s%d%c%s",
- theImpl->m_prefix.c_str(),
+ theImpl->m_systemPrefix.c_str(),
table->m_id,
table_name_separator,
external_name);
@@ -1324,6 +1468,12 @@ Ndb::pollEvents(int aMillisecondNumber, Uint64 *latestGCI)
return theEventBuffer->pollEvents(aMillisecondNumber, latestGCI);
}
+int
+Ndb::flushIncompleteEvents(Uint64 gci)
+{
+ return theEventBuffer->flushIncompleteEvents(gci);
+}
+
NdbEventOperation *Ndb::nextEvent()
{
return theEventBuffer->nextEvent();
diff --git a/storage/ndb/src/ndbapi/NdbDictionary.cpp b/storage/ndb/src/ndbapi/NdbDictionary.cpp
index e844dc3369e..c71689d2e81 100644
--- a/storage/ndb/src/ndbapi/NdbDictionary.cpp
+++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp
@@ -1618,6 +1618,14 @@ NdbDictionary::Dictionary::listIndexes(List& list,
return m_impl.listIndexes(list, tab->getTableId());
}
+int
+NdbDictionary::Dictionary::listIndexes(List& list,
+ const NdbDictionary::Table &table) const
+{
+ return m_impl.listIndexes(list, table.getTableId());
+}
+
+
const struct NdbError &
NdbDictionary::Dictionary::getNdbError() const {
return m_impl.getNdbError();
diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index 5a842d1ecc5..22a5d2f20a5 100644
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -56,7 +56,6 @@
DBUG_RETURN(b);\
}
-extern Uint64 g_latest_trans_gci;
int ndb_dictionary_is_mysqld = 0;
bool
@@ -1387,9 +1386,6 @@ NdbDictionaryImpl::putTable(NdbTableImpl *impl)
Ndb_local_table_info::create(impl, m_local_table_data_size);
m_localHash.put(impl->m_internalName.c_str(), info);
-
- m_ndb.theFirstTupleId[impl->getTableId()] = ~0;
- m_ndb.theLastTupleId[impl->getTableId()] = ~0;
}
int
@@ -1512,9 +1508,21 @@ NdbTableImpl *
NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index,
NdbTableImpl * table)
{
+ const char *current_db= m_ndb.getDatabaseName();
+ NdbTableImpl *index_table;
const BaseString internalName(
m_ndb.internalize_index_name(table, index->getName()));
- return getTable(m_ndb.externalizeTableName(internalName.c_str()));
+ // Get index table in system database
+ m_ndb.setDatabaseName(NDB_SYSTEM_DATABASE);
+ index_table= getTable(m_ndb.externalizeTableName(internalName.c_str()));
+ m_ndb.setDatabaseName(current_db);
+ if (!index_table)
+ {
+ // Index table not found
+ // Try geting index table in current database (old format)
+ index_table= getTable(m_ndb.externalizeTableName(internalName.c_str()));
+ }
+ return index_table;
}
#if 0
@@ -2249,11 +2257,11 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t)
}
if (autoIncrement) {
// XXX unlikely race condition - t.m_id may no longer be same table
- if (! m_ndb.setTupleIdInNdb(t.m_id, initialValue, false)) {
- if (m_ndb.theError.code)
- m_error.code = m_ndb.theError.code;
- else
- m_error.code = 4336;
+ // the tuple id range is not used on input
+ Ndb::TupleIdRange range;
+ if (m_ndb.setTupleIdInNdb(&t, range, initialValue, false) == -1) {
+ assert(m_ndb.theError.code != 0);
+ m_error.code = m_ndb.theError.code;
delete t2;
DBUG_RETURN(-1);
}
@@ -3002,63 +3010,6 @@ NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl)
DBUG_RETURN(0);
}
-/*****************************************************************
- * Get index info
- */
-NdbIndexImpl*
-NdbDictionaryImpl::getIndexImpl(const char * externalName,
- const BaseString& internalName)
-{
- ASSERT_NOT_MYSQLD;
- Ndb_local_table_info * info = get_local_table_info(internalName);
- if(info == 0){
- m_error.code = 4243;
- return 0;
- }
- NdbTableImpl * tab = info->m_table_impl;
-
- if(tab->m_indexType == NdbDictionary::Object::TypeUndefined)
- {
- // Not an index
- m_error.code = 4243;
- return 0;
- }
-
- NdbTableImpl* prim = getTable(tab->m_primaryTable.c_str());
- if(prim == 0){
- m_error.code = 4243;
- return 0;
- }
-
- return getIndexImpl(externalName, internalName, *tab, *prim);
-}
-
-NdbIndexImpl*
-NdbDictionaryImpl::getIndexImpl(const char * externalName,
- const BaseString& internalName,
- NdbTableImpl &tab,
- NdbTableImpl &prim)
-{
- DBUG_ENTER("NdbDictionaryImpl::getIndexImpl");
- DBUG_ASSERT(tab.m_indexType != NdbDictionary::Object::TypeUndefined);
- /**
- * Create index impl
- */
- NdbIndexImpl* idx;
- if(NdbDictInterface::create_index_obj_from_table(&idx, &tab, &prim) == 0){
- idx->m_table = &tab;
- idx->m_externalName.assign(externalName);
- idx->m_internalName.assign(internalName);
- idx->m_table_id = prim.getObjectId();
- idx->m_table_version = prim.getObjectVersion();
- // TODO Assign idx to tab->m_index
- // Don't do it right now since assign can't asign a table with index
- // tab->m_index = idx;
- DBUG_RETURN(idx);
- }
- DBUG_RETURN(0);
-}
-
int
NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
NdbTableImpl* tab,
@@ -3116,6 +3067,9 @@ NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
tab->m_columns[i]->m_distributionKey = 0;
}
+ idx->m_table_id = prim->getObjectId();
+ idx->m_table_version = prim->getObjectVersion();
+
* dst = idx;
DBUG_PRINT("exit", ("m_id: %d m_version: %d", idx->m_id, idx->m_version));
DBUG_RETURN(0);
@@ -4280,7 +4234,6 @@ NdbDictInterface::execWAIT_GCP_CONF(NdbApiSignal* signal,
{
const WaitGCPConf * const conf=
CAST_CONSTPTR(WaitGCPConf, signal->getDataPtr());
- g_latest_trans_gci= conf->gcp;
m_waiter.signal(NO_WAIT);
}
diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
index 5a7a1ebb0ab..b6961edd019 100644
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
@@ -617,6 +617,7 @@ public:
get_local_table_info(const BaseString& internalTableName);
NdbIndexImpl * getIndex(const char * indexName,
const char * tableName);
+ NdbIndexImpl * getIndex(const char * indexName, const NdbTableImpl& prim);
NdbEventImpl * getEvent(const char * eventName, NdbTableImpl* = NULL);
NdbEventImpl * getBlobEvent(const NdbEventImpl& ev, uint col_no);
NdbEventImpl * getEventImpl(const char * internalName);
@@ -950,59 +951,42 @@ NdbDictionaryImpl::get_local_table_info(const BaseString& internalTableName)
if (info)
{
m_localHash.put(internalTableName.c_str(), info);
- m_ndb.theFirstTupleId[tab->getTableId()] = ~0;
- m_ndb.theLastTupleId[tab->getTableId()] = ~0;
}
}
}
DBUG_RETURN(info); // autoincrement already initialized
}
-class InitIndexGlobal : public GlobalCacheInitObject
+class InitIndex : public GlobalCacheInitObject
{
public:
const char *m_index_name;
- NdbTableImpl &m_prim;
+ const NdbTableImpl &m_prim;
- InitIndexGlobal(NdbDictionaryImpl *dict,
- const BaseString &internal_indexname,
- const char *index_name,
- NdbTableImpl &prim) :
- GlobalCacheInitObject(dict, internal_indexname),
+ InitIndex(const BaseString &internal_indexname,
+ const char *index_name,
+ const NdbTableImpl &prim) :
+ GlobalCacheInitObject(0, internal_indexname),
m_index_name(index_name),
m_prim(prim)
- {}
- int init(NdbTableImpl &tab) const
- {
- tab.m_index= m_dict->getIndexImpl(m_index_name, m_name, tab, m_prim);
- if (tab.m_index == 0)
- return 1;
- tab.m_index->m_table= &tab;
- return 0;
- }
-};
-
-class InitIndex : public GlobalCacheInitObject
-{
-public:
- const char *m_index_name;
-
- InitIndex(NdbDictionaryImpl *dict,
- const BaseString &internal_indexname,
- const char *index_name) :
- GlobalCacheInitObject(dict, internal_indexname),
- m_index_name(index_name)
- {}
- int init(NdbTableImpl &tab) const
- {
- DBUG_ASSERT(tab.m_index == 0);
- tab.m_index= m_dict->getIndexImpl(m_index_name, m_name);
- if (tab.m_index)
+ {}
+
+ int init(NdbTableImpl &tab) const {
+ DBUG_ENTER("InitIndex::init");
+ DBUG_ASSERT(tab.m_indexType != NdbDictionary::Object::TypeUndefined);
+ /**
+ * Create index impl
+ */
+ NdbIndexImpl* idx;
+ if(NdbDictInterface::create_index_obj_from_table(&idx, &tab, &m_prim) == 0)
{
- tab.m_index->m_table= &tab;
- return 0;
+ idx->m_table = &tab;
+ idx->m_externalName.assign(m_index_name);
+ idx->m_internalName.assign(m_name);
+ tab.m_index = idx;
+ DBUG_RETURN(0);
}
- return 1;
+ DBUG_RETURN(1);
}
};
@@ -1019,14 +1003,14 @@ NdbDictionaryImpl::getIndexGlobal(const char * index_name,
while (retry)
{
NdbTableImpl *tab=
- fetchGlobalTableImplRef(InitIndexGlobal(this, internal_indexname,
- index_name, ndbtab));
+ fetchGlobalTableImplRef(InitIndex(internal_indexname,
+ index_name, ndbtab));
if (tab)
{
// tab->m_index sould be set. otherwise tab == 0
NdbIndexImpl *idx= tab->m_index;
- if (idx->m_table_id != ndbtab.getObjectId() ||
- idx->m_table_version != ndbtab.getObjectVersion())
+ if (idx->m_table_id != (unsigned)ndbtab.getObjectId() ||
+ idx->m_table_version != (unsigned)ndbtab.getObjectVersion())
{
releaseIndexGlobal(*idx, 1);
retry--;
@@ -1036,6 +1020,33 @@ NdbDictionaryImpl::getIndexGlobal(const char * index_name,
}
break;
}
+ {
+ // Index not found, try old format
+ const BaseString
+ old_internal_indexname(m_ndb.old_internalize_index_name(&ndbtab,
+ index_name));
+ retry= 2;
+ while (retry)
+ {
+ NdbTableImpl *tab=
+ fetchGlobalTableImplRef(InitIndex(old_internal_indexname,
+ index_name, ndbtab));
+ if (tab)
+ {
+ // tab->m_index sould be set. otherwise tab == 0
+ NdbIndexImpl *idx= tab->m_index;
+ if (idx->m_table_id != (unsigned)ndbtab.getObjectId() ||
+ idx->m_table_version != (unsigned)ndbtab.getObjectVersion())
+ {
+ releaseIndexGlobal(*idx, 1);
+ retry--;
+ continue;
+ }
+ DBUG_RETURN(idx);
+ }
+ break;
+ }
+ }
m_error.code= 4243;
DBUG_RETURN(0);
}
@@ -1067,41 +1078,78 @@ NdbIndexImpl *
NdbDictionaryImpl::getIndex(const char * index_name,
const char * table_name)
{
- while (table_name || m_ndb.usingFullyQualifiedNames())
+ if (table_name == 0)
{
- const BaseString internal_indexname(
- (table_name)
- ?
- m_ndb.internalize_index_name(getTable(table_name), index_name)
- :
- m_ndb.internalize_table_name(index_name)); // Index is also a table
-
- if (internal_indexname.length())
- {
- Ndb_local_table_info *info= m_localHash.get(internal_indexname.c_str());
- NdbTableImpl *tab;
- if (info == 0)
- {
- tab= fetchGlobalTableImplRef(InitIndex(this, internal_indexname,
- index_name));
- if (tab)
- {
- info= Ndb_local_table_info::create(tab, 0);
- if (info)
- m_localHash.put(internal_indexname.c_str(), info);
- else
- break;
- }
- else
- break;
- }
- else
- tab= info->m_table_impl;
- return tab->m_index;
- }
- break;
+ assert(0);
+ m_error.code= 4243;
+ return 0;
+ }
+
+
+ NdbTableImpl* prim = getTable(table_name);
+ if (prim == 0)
+ {
+ m_error.code= 4243;
+ return 0;
}
+ return getIndex(index_name, *prim);
+}
+
+inline
+NdbIndexImpl *
+NdbDictionaryImpl::getIndex(const char* index_name,
+ const NdbTableImpl& prim)
+{
+
+ const BaseString
+ internal_indexname(m_ndb.internalize_index_name(&prim, index_name));
+
+ Ndb_local_table_info *info= m_localHash.get(internal_indexname.c_str());
+ NdbTableImpl *tab;
+ if (info == 0)
+ {
+ tab= fetchGlobalTableImplRef(InitIndex(internal_indexname,
+ index_name,
+ prim));
+ if (!tab)
+ goto retry;
+
+ info= Ndb_local_table_info::create(tab, 0);
+ if (!info)
+ goto retry;
+ m_localHash.put(internal_indexname.c_str(), info);
+ }
+ else
+ tab= info->m_table_impl;
+
+ return tab->m_index;
+
+retry:
+ // Index not found, try fetching it from current database
+ const BaseString
+ old_internal_indexname(m_ndb.old_internalize_index_name(&prim, index_name));
+
+ info= m_localHash.get(old_internal_indexname.c_str());
+ if (info == 0)
+ {
+ tab= fetchGlobalTableImplRef(InitIndex(old_internal_indexname,
+ index_name,
+ prim));
+ if (!tab)
+ goto err;
+
+ info= Ndb_local_table_info::create(tab, 0);
+ if (!info)
+ goto err;
+ m_localHash.put(old_internal_indexname.c_str(), info);
+ }
+ else
+ tab= info->m_table_impl;
+
+ return tab->m_index;
+
+err:
m_error.code= 4243;
return 0;
}
diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
index 628ad5d925f..a5fbd84e5b0 100644
--- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
+++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
@@ -153,11 +153,14 @@ NdbEventOperationImpl::init(NdbEventImpl& evnt)
m_state= EO_CREATED;
+ m_node_bit_mask.clear();
#ifdef ndb_event_stores_merge_events_flag
m_mergeEvents = m_eventImpl->m_mergeEvents;
#else
- m_mergeEvents = false;
+ m_mergeEvents = false;
#endif
+ m_ref_count = 0;
+ DBUG_PRINT("info", ("m_ref_count = 0 for op: %p", this));
m_has_error= 0;
@@ -530,7 +533,11 @@ NdbEventOperationImpl::execute_nolock()
}
}
if (r == 0)
+ {
+ m_ref_count++;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", m_ref_count, this));
DBUG_RETURN(0);
+ }
}
//Error
m_state= EO_ERROR;
@@ -657,80 +664,79 @@ NdbEventOperationImpl::execSUB_TABLE_DATA(NdbApiSignal * signal,
int
NdbEventOperationImpl::receive_event()
{
- DBUG_ENTER_EVENT("NdbEventOperationImpl::receive_event");
-
Uint32 operation= (Uint32)m_data_item->sdata->operation;
- DBUG_PRINT_EVENT("info",("sdata->operation %u",operation));
-
- if (operation == NdbDictionary::Event::_TE_ALTER)
- {
- // Parse the new table definition and
- // create a table object
- NdbDictionary::Dictionary *myDict = m_ndb->getDictionary();
- NdbDictionaryImpl *dict = & NdbDictionaryImpl::getImpl(*myDict);
- NdbError error;
- NdbDictInterface dif(error);
- NdbTableImpl *at;
- m_change_mask = m_data_item->sdata->changeMask;
- error.code = dif.parseTableInfo(&at,
- (Uint32*)m_buffer.get_data(),
- m_buffer.length() / 4,
- true);
- m_buffer.clear();
- if (at)
- at->buildColumnHash();
- else
- {
- DBUG_PRINT_EVENT("info", ("Failed to parse DictTabInfo error %u",
- error.code));
- DBUG_RETURN_EVENT(1);
- }
-
- NdbTableImpl *tmp_table_impl= m_eventImpl->m_tableImpl;
- m_eventImpl->m_tableImpl = at;
-
- DBUG_PRINT("info", ("switching table impl 0x%x -> 0x%x",
- tmp_table_impl, at));
-
- // change the rec attrs to refer to the new table object
- int i;
- for (i = 0; i < 2; i++)
+ if (unlikely(operation >= NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT))
+ {
+ DBUG_ENTER("NdbEventOperationImpl::receive_event");
+ DBUG_PRINT("info",("sdata->operation %u this: %p", operation, this));
+ if (operation == NdbDictionary::Event::_TE_ALTER)
{
- NdbRecAttr *p = theFirstPkAttrs[i];
- while (p)
+ // Parse the new table definition and
+ // create a table object
+ NdbDictionary::Dictionary *myDict = m_ndb->getDictionary();
+ NdbDictionaryImpl *dict = & NdbDictionaryImpl::getImpl(*myDict);
+ NdbError error;
+ NdbDictInterface dif(error);
+ NdbTableImpl *at;
+ m_change_mask = m_data_item->sdata->changeMask;
+ error.code = dif.parseTableInfo(&at,
+ (Uint32*)m_buffer.get_data(),
+ m_buffer.length() / 4,
+ true);
+ m_buffer.clear();
+ if (unlikely(!at))
{
- int no = p->getColumn()->getColumnNo();
- NdbColumnImpl *tAttrInfo = at->getColumn(no);
- DBUG_PRINT("info", ("rec_attr: 0x%x "
- "switching column impl 0x%x -> 0x%x",
- p, p->m_column, tAttrInfo));
- p->m_column = tAttrInfo;
- p = p->next();
+ DBUG_PRINT("info", ("Failed to parse DictTabInfo error %u",
+ error.code));
+ ndbout_c("Failed to parse DictTabInfo error %u", error.code);
+ DBUG_RETURN(1);
}
- }
- for (i = 0; i < 2; i++)
- {
- NdbRecAttr *p = theFirstDataAttrs[i];
- while (p)
+ at->buildColumnHash();
+
+ NdbTableImpl *tmp_table_impl= m_eventImpl->m_tableImpl;
+ m_eventImpl->m_tableImpl = at;
+
+ DBUG_PRINT("info", ("switching table impl 0x%x -> 0x%x",
+ tmp_table_impl, at));
+
+ // change the rec attrs to refer to the new table object
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ NdbRecAttr *p = theFirstPkAttrs[i];
+ while (p)
+ {
+ int no = p->getColumn()->getColumnNo();
+ NdbColumnImpl *tAttrInfo = at->getColumn(no);
+ DBUG_PRINT("info", ("rec_attr: 0x%x "
+ "switching column impl 0x%x -> 0x%x",
+ p, p->m_column, tAttrInfo));
+ p->m_column = tAttrInfo;
+ p = p->next();
+ }
+ }
+ for (i = 0; i < 2; i++)
{
- int no = p->getColumn()->getColumnNo();
- NdbColumnImpl *tAttrInfo = at->getColumn(no);
- DBUG_PRINT("info", ("rec_attr: 0x%x "
- "switching column impl 0x%x -> 0x%x",
- p, p->m_column, tAttrInfo));
- p->m_column = tAttrInfo;
- p = p->next();
+ NdbRecAttr *p = theFirstDataAttrs[i];
+ while (p)
+ {
+ int no = p->getColumn()->getColumnNo();
+ NdbColumnImpl *tAttrInfo = at->getColumn(no);
+ DBUG_PRINT("info", ("rec_attr: 0x%x "
+ "switching column impl 0x%x -> 0x%x",
+ p, p->m_column, tAttrInfo));
+ p->m_column = tAttrInfo;
+ p = p->next();
+ }
}
+ if (tmp_table_impl)
+ delete tmp_table_impl;
}
- if (tmp_table_impl)
- delete tmp_table_impl;
- }
-
- if (unlikely(operation >= NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT))
- {
- DBUG_RETURN_EVENT(1);
+ DBUG_RETURN(1);
}
+ DBUG_ENTER_EVENT("NdbEventOperationImpl::receive_event");
+ DBUG_PRINT_EVENT("info",("sdata->operation %u this: %p", operation, this));
// now move the data into the RecAttrs
int is_update= operation == NdbDictionary::Event::_TE_UPDATE;
@@ -1089,6 +1095,33 @@ NdbEventBuffer::pollEvents(int aMillisecondNumber, Uint64 *latestGCI)
return ret;
}
+int
+NdbEventBuffer::flushIncompleteEvents(Uint64 gci)
+{
+ /**
+ * Find min complete gci
+ */
+ Uint32 i;
+ Uint32 sz= m_active_gci.size();
+ Gci_container* array = (Gci_container*)m_active_gci.getBase();
+ for(i = 0; i < sz; i++)
+ {
+ Gci_container* tmp = array + i;
+ if (tmp->m_gci && tmp->m_gci < gci)
+ {
+ // we have found an old not-completed gci, remove it
+ ndbout_c("ndb: flushing incomplete epoch %lld (<%lld)", tmp->m_gci, gci);
+ if(!tmp->m_data.is_empty())
+ {
+ free_list(tmp->m_data);
+ }
+ tmp->~Gci_container();
+ bzero(tmp, sizeof(Gci_container));
+ }
+ }
+ return 0;
+}
+
NdbEventOperation *
NdbEventBuffer::nextEvent()
{
@@ -1157,7 +1190,10 @@ NdbEventBuffer::nextEvent()
}
EventBufData_list::Gci_ops *gci_ops = m_available_data.first_gci_ops();
while (gci_ops && op->getGCI() > gci_ops->m_gci)
+ {
+ deleteUsedEventOperations();
gci_ops = m_available_data.next_gci_ops();
+ }
assert(gci_ops && (op->getGCI() == gci_ops->m_gci));
DBUG_RETURN_EVENT(op->m_facade);
}
@@ -1177,7 +1213,10 @@ NdbEventBuffer::nextEvent()
// free all "per gci unique" collected operations
EventBufData_list::Gci_ops *gci_ops = m_available_data.first_gci_ops();
while (gci_ops)
+ {
+ deleteUsedEventOperations();
gci_ops = m_available_data.next_gci_ops();
+ }
DBUG_RETURN_EVENT(0);
}
@@ -1191,31 +1230,37 @@ NdbEventBuffer::getGCIEventOperations(Uint32* iter, Uint32* event_types)
EventBufData_list::Gci_op g = gci_ops->m_gci_op_list[(*iter)++];
if (event_types != NULL)
*event_types = g.event_types;
- DBUG_PRINT("info", ("gci: %d", (unsigned)gci_ops->m_gci));
+ DBUG_PRINT("info", ("gci: %d g.op: %x g.event_types: %x",
+ (unsigned)gci_ops->m_gci, g.op, g.event_types));
DBUG_RETURN(g.op);
}
DBUG_RETURN(NULL);
}
void
-NdbEventBuffer::lock()
-{
- NdbMutex_Lock(m_mutex);
-}
-void
-NdbEventBuffer::unlock()
-{
- NdbMutex_Unlock(m_mutex);
-}
-void
-NdbEventBuffer::add_drop_lock()
+NdbEventBuffer::deleteUsedEventOperations()
{
- NdbMutex_Lock(p_add_drop_mutex);
-}
-void
-NdbEventBuffer::add_drop_unlock()
-{
- NdbMutex_Unlock(p_add_drop_mutex);
+ Uint32 iter= 0;
+ const NdbEventOperation *op_f;
+ while ((op_f= getGCIEventOperations(&iter, NULL)) != NULL)
+ {
+ NdbEventOperationImpl *op = &op_f->m_impl;
+ DBUG_ASSERT(op->m_ref_count > 0);
+ op->m_ref_count--;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", op->m_ref_count, op));
+ if (op->m_ref_count == 0)
+ {
+ DBUG_PRINT("info", ("deleting op: %p", op));
+ DBUG_ASSERT(op->m_node_bit_mask.isclear());
+ if (op->m_next)
+ op->m_next->m_prev = op->m_prev;
+ if (op->m_prev)
+ op->m_prev->m_next = op->m_next;
+ else
+ m_dropped_ev_op = op->m_next;
+ delete op->m_facade;
+ }
+ }
}
static
@@ -1469,6 +1514,10 @@ NdbEventBuffer::complete_outof_order_gcis()
void
NdbEventBuffer::report_node_failure(Uint32 node_id)
{
+ NdbEventOperation* op= m_ndb->getEventOperation(0);
+ if (op == 0)
+ return;
+
DBUG_ENTER("NdbEventBuffer::report_node_failure");
SubTableData data;
LinearSectionPtr ptr[3];
@@ -1484,12 +1533,20 @@ NdbEventBuffer::report_node_failure(Uint32 node_id)
/**
* Insert this event for each operation
*/
- NdbEventOperation* op= 0;
- while((op = m_ndb->getEventOperation(op)))
{
- NdbEventOperationImpl* impl= &op->m_impl;
- data.senderData = impl->m_oid;
- insertDataL(impl, &data, ptr);
+ // no need to lock()/unlock(), receive thread calls this
+ NdbEventOperationImpl* impl = &op->m_impl;
+ do if (!impl->m_node_bit_mask.isclear())
+ {
+ data.senderData = impl->m_oid;
+ insertDataL(impl, &data, ptr);
+ } while((impl = impl->m_next));
+ for (impl = m_dropped_ev_op; impl; impl = impl->m_next)
+ if (!impl->m_node_bit_mask.isclear())
+ {
+ data.senderData = impl->m_oid;
+ insertDataL(impl, &data, ptr);
+ }
}
DBUG_VOID_RETURN;
}
@@ -1515,12 +1572,21 @@ NdbEventBuffer::completeClusterFailed()
/**
* Insert this event for each operation
*/
- do
{
- NdbEventOperationImpl* impl= &op->m_impl;
- data.senderData = impl->m_oid;
- insertDataL(impl, &data, ptr);
- } while((op = m_ndb->getEventOperation(op)));
+ // no need to lock()/unlock(), receive thread calls this
+ NdbEventOperationImpl* impl = &op->m_impl;
+ do if (!impl->m_node_bit_mask.isclear())
+ {
+ data.senderData = impl->m_oid;
+ insertDataL(impl, &data, ptr);
+ } while((impl = impl->m_next));
+ for (impl = m_dropped_ev_op; impl; impl = impl->m_next)
+ if (!impl->m_node_bit_mask.isclear())
+ {
+ data.senderData = impl->m_oid;
+ insertDataL(impl, &data, ptr);
+ }
+ }
/**
* Release all GCI's with m_gci > gci
@@ -1565,7 +1631,11 @@ NdbEventBuffer::completeClusterFailed()
}
}
- assert(bucket != 0);
+ if (bucket == 0)
+ {
+ // no bucket to complete
+ DBUG_VOID_RETURN;
+ }
const Uint32 cnt= bucket->m_gcp_complete_rep_count = 1;
bucket->m_gci = gci;
@@ -1595,6 +1665,40 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op,
{
DBUG_ENTER_EVENT("NdbEventBuffer::insertDataL");
Uint64 gci= sdata->gci;
+ const bool is_data_event =
+ sdata->operation < NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT;
+
+ if (!is_data_event)
+ {
+ switch (sdata->operation)
+ {
+ case NdbDictionary::Event::_TE_NODE_FAILURE:
+ op->m_node_bit_mask.clear(sdata->ndbd_nodeid);
+ break;
+ case NdbDictionary::Event::_TE_ACTIVE:
+ op->m_node_bit_mask.set(sdata->ndbd_nodeid);
+ // internal event, do not relay to user
+ DBUG_RETURN_EVENT(0);
+ break;
+ case NdbDictionary::Event::_TE_CLUSTER_FAILURE:
+ op->m_node_bit_mask.clear();
+ DBUG_ASSERT(op->m_ref_count > 0);
+ op->m_ref_count--;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", op->m_ref_count, op));
+ break;
+ case NdbDictionary::Event::_TE_STOP:
+ op->m_node_bit_mask.clear(sdata->ndbd_nodeid);
+ if (op->m_node_bit_mask.isclear())
+ {
+ DBUG_ASSERT(op->m_ref_count > 0);
+ op->m_ref_count--;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", op->m_ref_count, op));
+ }
+ break;
+ default:
+ break;
+ }
+ }
if ( likely((Uint32)op->mi_type & (1 << (Uint32)sdata->operation)) )
{
@@ -1615,8 +1719,6 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op,
}
const bool is_blob_event = (op->theMainOp != NULL);
- const bool is_data_event =
- sdata->operation < NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT;
const bool use_hash = op->m_mergeEvents && is_data_event;
if (! is_data_event && is_blob_event)
@@ -2244,6 +2346,8 @@ void EventBufData_list::append_list(EventBufData_list *list, Uint64 gci)
void
EventBufData_list::add_gci_op(Gci_op g, bool del)
{
+ DBUG_ENTER_EVENT("EventBufData_list::add_gci_op");
+ DBUG_PRINT_EVENT("info", ("p.op: %p g.event_types: %x", g.op, g.event_types));
assert(g.op != NULL);
Uint32 i;
for (i = 0; i < m_gci_op_count; i++) {
@@ -2273,8 +2377,15 @@ EventBufData_list::add_gci_op(Gci_op g, bool del)
}
assert(m_gci_op_count < m_gci_op_alloc);
assert(! del);
+#ifndef DBUG_OFF
+ i = m_gci_op_count;
+#endif
+ g.op->m_ref_count++;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", g.op->m_ref_count, g.op));
m_gci_op_list[m_gci_op_count++] = g;
}
+ DBUG_PRINT_EVENT("exit", ("m_gci_op_list[%u].event_types: %x", i, m_gci_op_list[i].event_types));
+ DBUG_VOID_RETURN_EVENT;
}
void
@@ -2337,6 +2448,9 @@ NdbEventBuffer::createEventOperation(const char* eventName,
delete tOp;
DBUG_RETURN(NULL);
}
+ getEventOperationImpl(tOp)->m_ref_count = 1;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p",
+ getEventOperationImpl(tOp)->m_ref_count, getEventOperationImpl(tOp)));
DBUG_RETURN(tOp);
}
@@ -2362,16 +2476,10 @@ NdbEventBuffer::createEventOperation(NdbEventImpl& evnt,
void
NdbEventBuffer::dropEventOperation(NdbEventOperation* tOp)
{
+ DBUG_ENTER("NdbEventBuffer::dropEventOperation");
NdbEventOperationImpl* op= getEventOperationImpl(tOp);
op->stop();
-
- op->m_next= m_dropped_ev_op;
- op->m_prev= 0;
- if (m_dropped_ev_op)
- m_dropped_ev_op->m_prev= op;
- m_dropped_ev_op= op;
-
// stop blob event ops
if (op->theMainOp == NULL)
{
@@ -2391,11 +2499,24 @@ NdbEventBuffer::dropEventOperation(NdbEventOperation* tOp)
}
}
- // ToDo, take care of these to be deleted at the
- // appropriate time, after we are sure that there
- // are _no_ more events coming
-
- // delete tOp;
+ DBUG_ASSERT(op->m_ref_count > 0);
+ op->m_ref_count--;
+ DBUG_PRINT("info", ("m_ref_count: %u for op: %p", op->m_ref_count, op));
+ if (op->m_ref_count == 0)
+ {
+ DBUG_PRINT("info", ("deleting op: %p", op));
+ DBUG_ASSERT(op->m_node_bit_mask.isclear());
+ delete op->m_facade;
+ }
+ else
+ {
+ op->m_next= m_dropped_ev_op;
+ op->m_prev= 0;
+ if (m_dropped_ev_op)
+ m_dropped_ev_op->m_prev= op;
+ m_dropped_ev_op= op;
+ }
+ DBUG_VOID_RETURN;
}
void
diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp
index 70b3ce6b8de..bcae650bf44 100644
--- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp
+++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp
@@ -367,6 +367,8 @@ public:
Uint32 m_eventId;
Uint32 m_oid;
+ Bitmask<(unsigned int)_NDB_NODE_BITMASK_SIZE> m_node_bit_mask;
+ int m_ref_count;
bool m_mergeEvents;
EventBufData *m_data_item;
@@ -406,10 +408,10 @@ public:
void dropEventOperation(NdbEventOperation *);
static NdbEventOperationImpl* getEventOperationImpl(NdbEventOperation* tOp);
- void add_drop_lock();
- void add_drop_unlock();
- void lock();
- void unlock();
+ void add_drop_lock() { NdbMutex_Lock(p_add_drop_mutex); }
+ void add_drop_unlock() { NdbMutex_Unlock(p_add_drop_mutex); }
+ void lock() { NdbMutex_Lock(m_mutex); }
+ void unlock() { NdbMutex_Unlock(m_mutex); }
void add_op();
void remove_op();
@@ -430,9 +432,11 @@ public:
Uint32 getEventId(int bufferId);
int pollEvents(int aMillisecondNumber, Uint64 *latestGCI= 0);
+ int flushIncompleteEvents(Uint64 gci);
NdbEventOperation *nextEvent();
NdbEventOperationImpl* getGCIEventOperations(Uint32* iter,
Uint32* event_types);
+ void deleteUsedEventOperations();
NdbEventOperationImpl *move_data();
diff --git a/storage/ndb/src/ndbapi/NdbImpl.hpp b/storage/ndb/src/ndbapi/NdbImpl.hpp
index 82795550381..3b7b8cf44fb 100644
--- a/storage/ndb/src/ndbapi/NdbImpl.hpp
+++ b/storage/ndb/src/ndbapi/NdbImpl.hpp
@@ -93,6 +93,8 @@ public:
m_schemaname.c_str(), table_name_separator);
}
+ BaseString m_systemPrefix; // Buffer for preformatted for <sys>/<def>/
+
/**
* NOTE free lists must be _after_ theNdbObjectIdMap take
* assure that destructors are run in correct order
diff --git a/storage/ndb/src/ndbapi/NdbTransaction.cpp b/storage/ndb/src/ndbapi/NdbTransaction.cpp
index 3158dca5c40..916135b12d5 100644
--- a/storage/ndb/src/ndbapi/NdbTransaction.cpp
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp
@@ -32,6 +32,8 @@
#include <signaldata/TcKeyFailConf.hpp>
#include <signaldata/TcHbRep.hpp>
+Uint64 g_latest_trans_gci = 0;
+
/*****************************************************************************
NdbTransaction( Ndb* aNdb );
@@ -1568,6 +1570,9 @@ NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
theCommitStatus = Committed;
theCompletionStatus = CompletedSuccess;
theGlobalCheckpointId = commitConf->gci;
+ // theGlobalCheckpointId == 0 if NoOp transaction
+ if (theGlobalCheckpointId)
+ g_latest_trans_gci = theGlobalCheckpointId;
return 0;
} else {
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -1746,6 +1751,8 @@ from other transactions.
if (tCommitFlag == 1) {
theCommitStatus = Committed;
theGlobalCheckpointId = tGCI;
+ assert(tGCI);
+ g_latest_trans_gci = tGCI;
} else if ((tNoComp >= tNoSent) &&
(theLastExecOpInList->theCommitIndicator == 1)){
@@ -1922,6 +1929,8 @@ NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf,
if (tCommitFlag == 1) {
theCommitStatus = Committed;
theGlobalCheckpointId = tGCI;
+ assert(tGCI);
+ g_latest_trans_gci = tGCI;
} else if ((tNoComp >= tNoSent) &&
(theLastExecOpInList->theCommitIndicator == 1)){
/**********************************************************************/
diff --git a/storage/ndb/src/ndbapi/Ndbif.cpp b/storage/ndb/src/ndbapi/Ndbif.cpp
index 7799a71749e..ecaf6a3f435 100644
--- a/storage/ndb/src/ndbapi/Ndbif.cpp
+++ b/storage/ndb/src/ndbapi/Ndbif.cpp
@@ -46,7 +46,6 @@
#include <EventLogger.hpp>
extern EventLogger g_eventLogger;
-Uint64 g_latest_trans_gci= 0;
/******************************************************************************
* int init( int aNrOfCon, int aNrOfOp );
@@ -367,7 +366,6 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
(tCon->theSendStatus == NdbTransaction::sendTC_OP)) {
- g_latest_trans_gci= keyConf->gci;
tReturnCode = tCon->receiveTCKEYCONF(keyConf, tLen);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -520,7 +518,6 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
(tCon->theSendStatus == NdbTransaction::sendTC_COMMIT)) {
- g_latest_trans_gci= commitConf->gci;
tReturnCode = tCon->receiveTC_COMMITCONF(commitConf);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -855,7 +852,6 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
(tCon->theSendStatus == NdbTransaction::sendTC_OP)) {
- g_latest_trans_gci= indxConf->gci;
tReturnCode = tCon->receiveTCINDXCONF(indxConf, tLen);
if (tReturnCode != -1) {
completedTransaction(tCon);
diff --git a/storage/ndb/src/ndbapi/Ndbinit.cpp b/storage/ndb/src/ndbapi/Ndbinit.cpp
index e41380e6484..5c0fb521c36 100644
--- a/storage/ndb/src/ndbapi/Ndbinit.cpp
+++ b/storage/ndb/src/ndbapi/Ndbinit.cpp
@@ -100,10 +100,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection,
theConnectionArray[i] = NULL;
}//forg
m_sys_tab_0 = NULL;
- for (i = 0; i < 2048 ; i++) {
- theFirstTupleId[i] = 0;
- theLastTupleId[i] = 0;
- }//for
theImpl->m_dbname.assign(aDataBase);
theImpl->m_schemaname.assign(aSchema);
@@ -223,6 +219,9 @@ NdbImpl::NdbImpl(Ndb_cluster_connection *ndb_cluster_connection,
}
m_optimized_node_selection=
m_ndb_cluster_connection.m_optimized_node_selection;
+
+ m_systemPrefix.assfmt("%s%c%s%c", NDB_SYSTEM_DATABASE, table_name_separator,
+ NDB_SYSTEM_SCHEMA, table_name_separator);
}
NdbImpl::~NdbImpl()
diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c
index 8185bf38c3e..c05924dacf8 100644
--- a/storage/ndb/src/ndbapi/ndberror.c
+++ b/storage/ndb/src/ndbapi/ndberror.c
@@ -600,7 +600,6 @@ ErrorBundle ErrorCodes[] = {
{ 4269, DMEC, IE, "No connection to ndb management server" },
{ 4270, DMEC, IE, "Unknown blob error" },
{ 4335, DMEC, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" },
- { 4336, DMEC, AE, "Auto-increment value set below current value" },
{ 4271, DMEC, AE, "Invalid index object, not retrieved via getIndex()" },
{ 4272, DMEC, AE, "Table definition has undefined column" },
{ 4273, DMEC, IE, "No blob table in dict cache" },
diff --git a/storage/ndb/test/ndbapi/Makefile.am b/storage/ndb/test/ndbapi/Makefile.am
index 9a1e1c5e9ea..b55acd2420d 100644
--- a/storage/ndb/test/ndbapi/Makefile.am
+++ b/storage/ndb/test/ndbapi/Makefile.am
@@ -24,6 +24,7 @@ testOIBasic \
testOperations \
testRestartGci \
testScan \
+testInterpreter \
testScanInterpreter \
testScanPerf \
testSystemRestart \
@@ -64,6 +65,7 @@ testOIBasic_SOURCES = testOIBasic.cpp
testOperations_SOURCES = testOperations.cpp
testRestartGci_SOURCES = testRestartGci.cpp
testScan_SOURCES = testScan.cpp ScanFunctions.hpp
+testInterpreter_SOURCES = testInterpreter.cpp
testScanInterpreter_SOURCES = testScanInterpreter.cpp ScanFilter.hpp ScanInterpretTest.hpp
testScanPerf_SOURCES = testScanPerf.cpp
testSystemRestart_SOURCES = testSystemRestart.cpp
diff --git a/storage/ndb/test/ndbapi/testDict.cpp b/storage/ndb/test/ndbapi/testDict.cpp
index 7ade359342d..b015e16bae1 100644
--- a/storage/ndb/test/ndbapi/testDict.cpp
+++ b/storage/ndb/test/ndbapi/testDict.cpp
@@ -1139,9 +1139,13 @@ runCreateAutoincrementTable(NDBT_Context* ctx, NDBT_Step* step){
for (int i = 0; i < 16; i++) {
- Uint64 value = myNdb->getAutoIncrementValue(tabname, 1);
-
- if (value != (startvalue+i)) {
+ Uint64 value;
+ if (myNdb->getAutoIncrementValue(tabname, value, 1) == -1) {
+ g_err << "getAutoIncrementValue failed on " << tabname << endl;
+ APIERROR(myNdb->getNdbError());
+ return NDBT_FAILED;
+ }
+ else if (value != (startvalue+i)) {
g_err << "value = " << value << " expected " << startvalue+i << endl;;
APIERROR(myNdb->getNdbError());
// ret = NDBT_FAILED;
diff --git a/storage/ndb/test/ndbapi/testInterpreter.cpp b/storage/ndb/test/ndbapi/testInterpreter.cpp
index 0baba33d2b2..5d930d3d555 100644
--- a/storage/ndb/test/ndbapi/testInterpreter.cpp
+++ b/storage/ndb/test/ndbapi/testInterpreter.cpp
@@ -79,46 +79,46 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){
Ndb* pNdb = GETNDB(step);
- NdbConnection* pTrans = pNdb->startTransaction();
- if (pTrans == NULL){
- ERR(pNdb->getNdbError());
- return NDBT_FAILED;
- }
-
- NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- int check = pOp->interpretedUpdateTuple();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
-
- // Primary keys
- Uint32 pkVal = 1;
- check = pOp->equal("KOL1", pkVal );
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- // Attributes
-
- // Update column
- Uint32 valToIncWith = 1;
- check = pOp->incValue("KOL2", valToIncWith);
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
+ NdbConnection* pTrans = pNdb->startTransaction();
+ if (pTrans == NULL){
+ ERR(pNdb->getNdbError());
+ return NDBT_FAILED;
+ }
+
+ NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName());
+ if (pOp == NULL) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ int check = pOp->interpretedUpdateTuple();
+ if( check == -1 ) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+
+ // Primary keys
+ Uint32 pkVal = 1;
+ check = pOp->equal("KOL1", pkVal );
+ if( check == -1 ) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ // Attributes
+
+ // Update column
+ Uint32 valToIncWith = 1;
+ check = pOp->incValue("KOL2", valToIncWith);
+ if( check == -1 ) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
NdbRecAttr* valueRec = pOp->getValue("KOL2");
if( valueRec == NULL ) {
@@ -142,6 +142,122 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_OK;
}
+int runTestBug19537(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ const NdbDictionary::Table * pTab = ctx->getTab();
+ Ndb* pNdb = GETNDB(step);
+
+ if (strcmp(pTab->getName(), "T1") != 0) {
+ g_err << "runTestBug19537: skip, table != T1" << endl;
+ return NDBT_OK;
+ }
+
+
+ NdbConnection* pTrans = pNdb->startTransaction();
+ if (pTrans == NULL){
+ ERR(pNdb->getNdbError());
+ return NDBT_FAILED;
+ }
+
+ NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName());
+ if (pOp == NULL) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (pOp->interpretedUpdateTuple() == -1) {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+
+ // Primary keys
+ const Uint32 pkVal = 1;
+ if (pOp->equal("KOL1", pkVal) == -1) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ // Load 64-bit constant into register 1 and
+ // write from register 1 to 32-bit column KOL2
+ const Uint64 reg_val = 0x0102030405060708ULL;
+
+ const Uint32* reg_ptr32 = (const Uint32*)&reg_val;
+ if (reg_ptr32[0] == 0x05060708 && reg_ptr32[1] == 0x01020304) {
+ g_err << "runTestBug19537: platform is LITTLE endian" << endl;
+ } else if (reg_ptr32[0] == 0x01020304 && reg_ptr32[1] == 0x05060708) {
+ g_err << "runTestBug19537: platform is BIG endian" << endl;
+ } else {
+ g_err << "runTestBug19537: impossible platform"
+ << hex << " [0]=" << reg_ptr32[0] << " [1]=" <<reg_ptr32[1] << endl;
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (pOp->load_const_u64(1, reg_val) == -1 ||
+ pOp->write_attr("KOL2", 1) == -1) {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (pTrans->execute(Commit) == -1) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ // Read value via a new transaction
+
+ pTrans = pNdb->startTransaction();
+ if (pTrans == NULL){
+ ERR(pNdb->getNdbError());
+ return NDBT_FAILED;
+ }
+
+ pOp = pTrans->getNdbOperation(pTab->getName());
+ if (pOp == NULL) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ Uint32 kol2 = 0x09090909;
+ if (pOp->readTuple() == -1 ||
+ pOp->equal("KOL1", pkVal) == -1 ||
+ pOp->getValue("KOL2", (char*)&kol2) == 0) {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (pTrans->execute(Commit) == -1) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ // Expected conversion as in C - truncate to lower (logical) word
+
+ if (kol2 == 0x01020304) {
+ g_err << "runTestBug19537: the bug manifests itself !" << endl;
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (kol2 != 0x05060708) {
+ g_err << "runTestBug19537: impossible KOL2 " << hex << kol2 << endl;
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ pNdb->closeTransaction(pTrans);
+ return NDBT_OK;
+}
+
NDBT_TESTSUITE(testInterpreter);
TESTCASE("IncValue32",
@@ -156,6 +272,12 @@ TESTCASE("IncValue64",
INITIALIZER(runTestIncValue64);
FINALIZER(runClearTable);
}
+TESTCASE("Bug19537",
+ "Test big-endian write_attr of 32 bit integer\n"){
+ INITIALIZER(runLoadTable);
+ INITIALIZER(runTestBug19537);
+ FINALIZER(runClearTable);
+}
#if 0
TESTCASE("MaxTransactions",
"Start transactions until no more can be created\n"){
diff --git a/storage/ndb/test/ndbapi/testNodeRestart.cpp b/storage/ndb/test/ndbapi/testNodeRestart.cpp
index aed0b39f196..754b3edc269 100644
--- a/storage/ndb/test/ndbapi/testNodeRestart.cpp
+++ b/storage/ndb/test/ndbapi/testNodeRestart.cpp
@@ -868,6 +868,56 @@ runBug18612SR(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_OK;
}
+int runBug20185(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ NdbRestarter restarter;
+ HugoOperations hugoOps(*ctx->getTab());
+ Ndb* pNdb = GETNDB(step);
+
+ int dump[] = { 7090, 20 } ;
+ if (restarter.dumpStateAllNodes(dump, 2))
+ return NDBT_FAILED;
+
+ NdbSleep_MilliSleep(3000);
+
+ if(hugoOps.startTransaction(pNdb) != 0)
+ return NDBT_FAILED;
+
+ if(hugoOps.pkUpdateRecord(pNdb, 1, 1) != 0)
+ return NDBT_FAILED;
+
+ if (hugoOps.execute_NoCommit(pNdb) != 0)
+ return NDBT_FAILED;
+
+ int nodeId;
+ const int node = hugoOps.getTransaction()->getConnectedNodeId();
+ do {
+ nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes());
+ } while (nodeId == node);
+
+ if (restarter.insertErrorInAllNodes(7030))
+ return NDBT_FAILED;
+
+ if (restarter.insertErrorInNode(nodeId, 7031))
+ return NDBT_FAILED;
+
+ NdbSleep_MilliSleep(500);
+
+ if (hugoOps.execute_Commit(pNdb) == 0)
+ return NDBT_FAILED;
+
+ NdbSleep_MilliSleep(3000);
+
+ restarter.waitClusterStarted();
+
+ if (restarter.dumpStateAllNodes(dump, 1))
+ return NDBT_FAILED;
+
+ return NDBT_OK;
+}
+
NDBT_TESTSUITE(testNodeRestart);
TESTCASE("NoLoad",
@@ -1175,6 +1225,12 @@ TESTCASE("Bug18612SR",
STEP(runBug18612SR);
FINALIZER(runClearTable);
}
+TESTCASE("Bug20185",
+ ""){
+ INITIALIZER(runLoadTable);
+ STEP(runBug20185);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNodeRestart);
int main(int argc, const char** argv){
diff --git a/storage/ndb/test/run-test/daily-basic-tests.txt b/storage/ndb/test/run-test/daily-basic-tests.txt
index 3fead45533f..5fe3506dffb 100644
--- a/storage/ndb/test/run-test/daily-basic-tests.txt
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt
@@ -473,6 +473,10 @@ max-time: 1000
cmd: testNodeRestart
args: -n Bug18612SR T1
+max-time: 1000
+cmd: testNodeRestart
+args: -n Bug20185 T1
+
#
# DICT TESTS
max-time: 1500
diff --git a/storage/ndb/tools/restore/consumer_restore.cpp b/storage/ndb/tools/restore/consumer_restore.cpp
index 3b39a1373a0..6b0d42ee0d2 100644
--- a/storage/ndb/tools/restore/consumer_restore.cpp
+++ b/storage/ndb/tools/restore/consumer_restore.cpp
@@ -151,9 +151,12 @@ BackupRestore::finalize_table(const TableS & table){
if (table.have_auto_inc())
{
Uint64 max_val= table.get_max_auto_val();
- Uint64 auto_val= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable));
- if (max_val+1 > auto_val || auto_val == ~(Uint64)0)
- ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false);
+ Uint64 auto_val;
+ int r= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable), auto_val);
+ if (r == -1 && m_ndb->getNdbError().code != 626)
+ ret= false;
+ else if (r == -1 || max_val+1 > auto_val)
+ ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false) != -1;
}
return ret;
}
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index bf17375c0eb..bd16297f8e7 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -265,7 +265,10 @@ case "$mode" in
then
# Give extra arguments to mysqld with the my.cnf file. This script may
# be overwritten at next upgrade.
- $manager --user=$user --pid-file=$pid_file >/dev/null 2>&1 &
+ "$manager" \
+ --mysqld-safe-compatible \
+ --user="$user" \
+ --pid-file="$pid_file" >/dev/null 2>&1 &
wait_for_pid created
# Make lock for RedHat / SuSE
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 9b15806f880..01746d3156e 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -217,6 +217,7 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \
--with-fast-mutexes \
--with-mysqld-user=%{mysqld_user} \
--with-unix-socket-path=/var/lib/mysql/mysql.sock \
+ --with-pic \
--prefix=/ \
--with-extra-charsets=all \
%if %{YASSL_BUILD}
@@ -319,7 +320,7 @@ BuildMySQL "--enable-shared \
--with-example-storage-engine \
--with-blackhole-storage-engine \
--with-federated-storage-engine \
- --with-big-tables \
+ --with-big-tables \
--with-comment=\"MySQL Community Server - Max (GPL)\"")
# We might want to save the config log file
@@ -553,7 +554,6 @@ fi
%attr(755, root, root) %{_bindir}/myisampack
%attr(755, root, root) %{_bindir}/mysql_convert_table_format
%attr(755, root, root) %{_bindir}/mysql_create_system_tables
-%attr(755, root, root) %{_bindir}/mysql_explain_log
%attr(755, root, root) %{_bindir}/mysql_fix_extensions
%attr(755, root, root) %{_bindir}/mysql_fix_privilege_tables
%attr(755, root, root) %{_bindir}/mysql_install_db
@@ -683,12 +683,15 @@ fi
# itself - note that they must be ordered by date (important when
# merging BK trees)
%changelog
- %changelog
+* Sat May 20 2006 Kent Boortz <kent@mysql.com>
+
+- Always compile for PIC, position independent code.
+
* Wed May 10 2006 Kent Boortz <kent@mysql.com>
-- Use character set "all" for the "max", to make Cluster nodes
- independent on the character set directory, and the problem that
- two RPM sub packages both wants to install this directory.
+- Use character set "all" when compiling with Cluster, to make Cluster
+ nodes independent on the character set directory, and the problem
+ that two RPM sub packages both wants to install this directory.
* Mon May 01 2006 Kent Boortz <kent@mysql.com>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e9432a4c9d2..8ee64f8179c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -22,6 +22,13 @@ if HAVE_YASSL
else
yassl_dummy_link_fix=
endif
+
+if THREAD_SAFE_CLIENT
+LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql_r/libmysqlclient_r.la
+else
+LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql/libmysqlclient.la
+endif
+
EXTRA_DIST = auto_increment.res auto_increment.tst \
function.res function.tst lock_test.pl lock_test.res \
export.pl big_record.pl \
@@ -42,7 +49,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
$(openssl_includes)
LIBS = @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ \
- $(top_builddir)/libmysql/libmysqlclient.la
+ $(LIBMYSQLCLIENT_LA)
mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) -L../mysys -lmysys
mysql_client_test_SOURCES= mysql_client_test.c $(yassl_dummy_link_fix)
insert_test_SOURCES= insert_test.c $(yassl_dummy_link_fix)
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index d927b27ab37..e3159cfa5e5 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -12794,25 +12794,26 @@ from t2);");
static void test_bug8378()
{
#if defined(HAVE_CHARSET_gbk) && !defined(EMBEDDED_LIBRARY)
- MYSQL *lmysql;
+ MYSQL *old_mysql=mysql;
char out[9]; /* strlen(TEST_BUG8378)*2+1 */
- int len;
+ char buf[256];
+ int len, rc;
myheader("test_bug8378");
if (!opt_silent)
fprintf(stdout, "\n Establishing a test connection ...");
- if (!(lmysql= mysql_init(NULL)))
+ if (!(mysql= mysql_init(NULL)))
{
myerror("mysql_init() failed");
exit(1);
}
- if (mysql_options(lmysql, MYSQL_SET_CHARSET_NAME, "gbk"))
+ if (mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk"))
{
myerror("mysql_options() failed");
exit(1);
}
- if (!(mysql_real_connect(lmysql, opt_host, opt_user,
+ if (!(mysql_real_connect(mysql, opt_host, opt_user,
opt_password, current_db, opt_port,
opt_unix_socket, 0)))
{
@@ -12822,12 +12823,18 @@ static void test_bug8378()
if (!opt_silent)
fprintf(stdout, " OK");
- len= mysql_real_escape_string(lmysql, out, TEST_BUG8378_IN, 4);
+ len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
/* No escaping should have actually happened. */
DIE_UNLESS(memcmp(out, TEST_BUG8378_OUT, len) == 0);
- mysql_close(lmysql);
+ sprintf(buf, "SELECT '%s'", out);
+ rc=mysql_real_query(mysql, buf, strlen(buf));
+ myquery(rc);
+
+ mysql_close(mysql);
+
+ mysql=old_mysql;
#endif
}
diff --git a/unittest/Makefile.am b/unittest/Makefile.am
index fd7530ee262..ca3291efde0 100644
--- a/unittest/Makefile.am
+++ b/unittest/Makefile.am
@@ -1,27 +1,15 @@
SUBDIRS = mytap . mysys examples
noinst_SCRIPTS = unit
+EXTRA_DIST = unit.pl
+CLEANFILES = unit
-EXTRA_DIST = unit.pl
+unittests = mytap mysys
-DISTCLEANFILES = unit
-
-unittests = mysys examples
-
-.PHONY: all mytap mysys examples test
-
-test: unit all
- @./unit run $(unittests)
-
-mytap:
- cd mytap && $(MAKE)
-
-mysys:
- cd mysys && $(MAKE)
-
-examples:
- cd examples && $(MAKE)
+test: unit
+ ./unit run $(unittests)
unit: $(srcdir)/unit.pl
- cp $< $@
- chmod +x $@
+ cp $(srcdir)/unit.pl $@
+ chmod 700 $@
+
diff --git a/unittest/README.txt b/unittest/README.txt
index fd9641665c7..0d8bb9025d8 100644
--- a/unittest/README.txt
+++ b/unittest/README.txt
@@ -7,14 +7,14 @@ will be added over time.
mytap Source for the MyTAP library
mysys Tests for mysys components
- bitmap.t.c Unit test for MY_BITMAP
- base64.t.c Unit test for base64 encoding functions
+ bitmap-t.c Unit test for MY_BITMAP
+ base64-t.c Unit test for base64 encoding functions
examples Example unit tests
- simple.t.c Example of a standard TAP unit test
- skip.t.c Example where some test points are skipped
- skip_all.t.c Example of a test where the entire test is skipped
- todo.t.c Example where test contain test points that are TODO
- no_plan.t.c Example of a test with no plan (avoid this)
+ simple-t.c Example of a standard TAP unit test
+ skip-t.c Example where some test points are skipped
+ skip_all-t.c Example of a test where the entire test is skipped
+ todo-t.c Example where test contain test points that are TODO
+ no_plan-t.c Example of a test with no plan (avoid this)
Executing unit tests
@@ -28,9 +28,12 @@ To make and execute all unit tests in the directory:
Adding unit tests
-----------------
-Add a file with a name of the format "foo.t.c" to the appropriate
+Add a file with a name of the format "foo-t.c" to the appropriate
directory and add the following to the Makefile.am in that directory
(where ... denotes stuff already there):
- noinst_PROGRAMS = ... foo.t
- foo_t_c_SOURCES = foo.t.c
+ noinst_PROGRAMS = ... foo-t
+
+Note, it's important to have "-t" at the end of the filename, otherwise the
+test won't be executed by 'make test' !
+
diff --git a/unittest/examples/Makefile.am b/unittest/examples/Makefile.am
index 94a67927d12..f3c70b654a1 100644
--- a/unittest/examples/Makefile.am
+++ b/unittest/examples/Makefile.am
@@ -5,14 +5,5 @@ AM_LDFLAGS = -L$(top_builddir)/unittest/mytap
LDADD = -lmytap
-noinst_PROGRAMS = simple.t skip.t todo.t skip_all.t no_plan.t
+noinst_PROGRAMS = simple-t skip-t todo-t skip_all-t no_plan-t
-simple_t_SOURCES = simple.t.c
-
-skip_t_SOURCES = skip.t.c
-
-todo_t_SOURCES = todo.t.c
-
-skip_all_t_SOURCES = skip_all.t.c
-
-no_plan_t_SOURCES = no_plan.t.c
diff --git a/unittest/examples/no_plan.t.c b/unittest/examples/no_plan-t.c
index 98e4d06def6..98e4d06def6 100644
--- a/unittest/examples/no_plan.t.c
+++ b/unittest/examples/no_plan-t.c
diff --git a/unittest/examples/simple.t.c b/unittest/examples/simple-t.c
index 866af865327..866af865327 100644
--- a/unittest/examples/simple.t.c
+++ b/unittest/examples/simple-t.c
diff --git a/unittest/examples/skip.t.c b/unittest/examples/skip-t.c
index ef717691700..ef717691700 100644
--- a/unittest/examples/skip.t.c
+++ b/unittest/examples/skip-t.c
diff --git a/unittest/examples/skip_all.t.c b/unittest/examples/skip_all-t.c
index 19b8c1fddaf..19b8c1fddaf 100644
--- a/unittest/examples/skip_all.t.c
+++ b/unittest/examples/skip_all-t.c
diff --git a/unittest/examples/todo.t.c b/unittest/examples/todo-t.c
index 82601bee41c..82601bee41c 100644
--- a/unittest/examples/todo.t.c
+++ b/unittest/examples/todo-t.c
diff --git a/unittest/mysys/Makefile.am b/unittest/mysys/Makefile.am
index 010a7845339..b1e0356bac6 100644
--- a/unittest/mysys/Makefile.am
+++ b/unittest/mysys/Makefile.am
@@ -7,9 +7,5 @@ AM_LDFLAGS += -L$(top_builddir)/strings -L$(top_builddir)/dbug
LDADD = -lmytap -lmysys -ldbug -lmystrings
-noinst_PROGRAMS = bitmap.t base64.t
-
-bitmap_t_SOURCES = bitmap.t.c
-
-base64_t_SOURCES = base64.t.c
+noinst_PROGRAMS = bitmap-t base64-t my_atomic-t
diff --git a/unittest/mysys/base64.t.c b/unittest/mysys/base64-t.c
index 1b4f2eb2356..6d85964b20d 100644
--- a/unittest/mysys/base64.t.c
+++ b/unittest/mysys/base64-t.c
@@ -15,9 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA */
+#include <my_global.h>
#include <base64.h>
#include <tap.h>
-#include <stdlib.h>
#include <string.h>
int
diff --git a/unittest/mysys/bitmap.t.c b/unittest/mysys/bitmap-t.c
index d5683baff66..d5683baff66 100644
--- a/unittest/mysys/bitmap.t.c
+++ b/unittest/mysys/bitmap-t.c
diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c
new file mode 100644
index 00000000000..8a3fe129b07
--- /dev/null
+++ b/unittest/mysys/my_atomic-t.c
@@ -0,0 +1,149 @@
+/* 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 */
+
+#include <tap.h>
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+
+my_atomic_32_t a32,b32,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)
+{
+ int m=*(int *)arg;
+ int32 x;
+ for (x=((int)(&m)); m ; m--)
+ {
+ x=x*m+0x87654321;
+ my_atomic_add32(&a32, x, &rwl);
+ my_atomic_add32(&a32, -x, &rwl);
+ }
+ pthread_mutex_lock(&mutex);
+ N--;
+ if (!N) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+
+/*
+ 1. generate thread number 0..N-1 from b32
+ 2. add it to a32
+ 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
+*/
+pthread_handler_t test_atomic_swap_handler(void *arg)
+{
+ int m=*(int *)arg;
+ uint32 x=my_atomic_add32(&b32, 1, &rwl);
+
+ my_atomic_add32(&a32, x, &rwl);
+
+ for (; m ; m--)
+ x=my_atomic_swap32(&c32, x,&rwl);
+
+ if (!x)
+ x=my_atomic_swap32(&c32, x,&rwl);
+
+ my_atomic_add32(&a32, -x, &rwl);
+
+ pthread_mutex_lock(&mutex);
+ N--;
+ if (!N) 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
+*/
+pthread_handler_t test_atomic_cas_handler(void *arg)
+{
+ int m=*(int *)arg;
+ int32 x;
+ for (x=((int)(&m)); m ; m--)
+ {
+ uint32 y=my_atomic_load32(&a32, &rwl);
+ x=x*m+0x87654321;
+ while (!my_atomic_cas32(&a32, &y, y+x, &rwl)) ;
+ while (!my_atomic_cas32(&a32, &y, y-x, &rwl)) ;
+ }
+ pthread_mutex_lock(&mutex);
+ N--;
+ if (!N) 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();
+
+ my_atomic_store32(&a32, 0, &rwl);
+ my_atomic_store32(&b32, 0, &rwl);
+ my_atomic_store32(&c32, 0, &rwl);
+
+ diag("Testing %s with %d threads, %d iterations... ", test, n, m);
+ for (N=n ; n ; n--)
+ pthread_create(&t, &thr_attr, handler, &m);
+
+ pthread_mutex_lock(&mutex);
+ while (N)
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ now=my_getsystime()-now;
+ ok(my_atomic_load32(&a32, &rwl) == 0,
+ "tested %s in %g secs", test, ((double)now)/1e7);
+}
+
+int main()
+{
+ int err;
+
+ 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);
+ my_atomic_rwlock_init(&rwl);
+
+ test_atomic("my_atomic_add32", test_atomic_add_handler, 100,1000000);
+ test_atomic("my_atomic_swap32", test_atomic_swap_handler, 100,1000000);
+ test_atomic("my_atomic_cas32", test_atomic_cas_handler, 100,1000000);
+
+ pthread_mutex_destroy(&mutex);
+ pthread_cond_destroy(&cond);
+ pthread_attr_destroy(&thr_attr);
+ my_atomic_rwlock_destroy(&rwl);
+ return exit_status();
+}
+
diff --git a/unittest/mytap/t/Makefile.am b/unittest/mytap/t/Makefile.am
index 88c31cfeb7f..b685ae7dc1c 100644
--- a/unittest/mytap/t/Makefile.am
+++ b/unittest/mytap/t/Makefile.am
@@ -5,8 +5,5 @@ AM_LDFLAGS = -L$(top_builddir)/unittest/mytap
LDADD = -lmytap
-noinst_PROGRAMS = basic.t
+noinst_PROGRAMS = basic-t
-basic_t_SOURCES = basic.t.c
-
-all: $(noinst_PROGRAMS)
diff --git a/unittest/mytap/t/basic.t.c b/unittest/mytap/t/basic-t.c
index 95a77755347..bf4c1a9a664 100644
--- a/unittest/mytap/t/basic.t.c
+++ b/unittest/mytap/t/basic-t.c
@@ -2,7 +2,7 @@
#include "my_config.h"
#include <stdlib.h>
-#include <tap.h>
+#include "../tap.h"
int main() {
plan(5);
diff --git a/unittest/unit.pl b/unittest/unit.pl
index cae394cf9b6..3092a874192 100644
--- a/unittest/unit.pl
+++ b/unittest/unit.pl
@@ -59,7 +59,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/;
}, @dirs;
return @files;
}
diff --git a/vio/Makefile.am b/vio/Makefile.am
index e1830fdc636..b57f2453f41 100644
--- a/vio/Makefile.am
+++ b/vio/Makefile.am
@@ -20,7 +20,7 @@ else
yassl_dummy_link_fix=
endif
INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \
- $(openssl_includes) $(yassl_includes)
+ $(openssl_includes)
LDADD= @CLIENT_EXTRA_LDFLAGS@ $(openssl_libs) $(yassl_libs)
pkglib_LIBRARIES= libvio.a
noinst_PROGRAMS = test-ssl test-sslserver test-sslclient
diff --git a/vio/viosocket.c b/vio/viosocket.c
index 0ddceb72e91..78901fedb69 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -33,7 +33,8 @@ int vio_read(Vio * vio, gptr buf, int size)
{
int r;
DBUG_ENTER("vio_read");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
/* Ensure nobody uses vio_read_buff and vio_read simultaneously */
DBUG_ASSERT(vio->read_end == vio->read_pos);
@@ -64,7 +65,8 @@ int vio_read_buff(Vio *vio, gptr buf, int size)
int rc;
#define VIO_UNBUFFERED_READ_MIN_SIZE 2048
DBUG_ENTER("vio_read_buff");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
if (vio->read_pos < vio->read_end)
{
@@ -102,7 +104,8 @@ int vio_write(Vio * vio, const gptr buf, int size)
{
int r;
DBUG_ENTER("vio_write");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
#ifdef __WIN__
r = send(vio->sd, buf, size,0);
#else
@@ -223,7 +226,7 @@ int vio_keepalive(Vio* vio, my_bool set_keep_alive)
int r=0;
uint opt = 0;
DBUG_ENTER("vio_keepalive");
- DBUG_PRINT("enter", ("sd: %d, set_keep_alive: %d", vio->sd, (int)
+ DBUG_PRINT("enter", ("sd: %d set_keep_alive: %d", vio->sd, (int)
set_keep_alive));
if (vio->type != VIO_TYPE_NAMEDPIPE)
{
@@ -393,7 +396,8 @@ int vio_read_pipe(Vio * vio, gptr buf, int size)
{
DWORD length;
DBUG_ENTER("vio_read_pipe");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
DBUG_RETURN(-1);
@@ -407,7 +411,8 @@ int vio_write_pipe(Vio * vio, const gptr buf, int size)
{
DWORD length;
DBUG_ENTER("vio_write_pipe");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
DBUG_RETURN(-1);
@@ -452,7 +457,8 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size)
char *current_postion;
DBUG_ENTER("vio_read_shared_memory");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
remain_local = size;
current_postion=buf;
@@ -513,7 +519,8 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size)
char *current_postion;
DBUG_ENTER("vio_write_shared_memory");
- DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, (long) buf,
+ size));
remain = size;
current_postion = buf;