summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <pappa@c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se>2005-08-25 13:11:38 -0400
committerunknown <pappa@c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se>2005-08-25 13:11:38 -0400
commit5c0dc1ace8b803f799c328fae1c6d40c2b47f5ea (patch)
tree86faf87634c19937967b360a0dd1413fc9eb2879
parentda2ff990c7e7f0a8796f43513277b8a8322102ce (diff)
parent7887d8b808b4938e1d3673824afb4c4604018274 (diff)
downloadmariadb-git-5c0dc1ace8b803f799c328fae1c6d40c2b47f5ea.tar.gz
Merge mronstrom@bk-internal.mysql.com:/home/bk/mysql-5.0
into c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/mysql-5.1 BitKeeper/deleted/.del-Grep.cpp~ad798e9ae519d667: Auto merged BitKeeper/deleted/.del-Grep.hpp~b05e3af6cfabe387: Auto merged BitKeeper/deleted/.del-GrepInit.cpp~df28ab3a892455fd: Auto merged BitKeeper/deleted/.del-Makefile.am~f73be89578d3b6cc: Auto merged BitKeeper/deleted/.del-Makefile~b293ae88e4394490: Auto merged BitKeeper/deleted/.del-Makefile~e0b7d67078f0fae0: Auto merged BitKeeper/deleted/.del-grep_systab_test.cpp~c7305578bec8cb62: Auto merged BitKeeper/etc/config: Auto merged config/ac-macros/ha_ndbcluster.m4: Auto merged include/my_global.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged BitKeeper/deleted/.del-testGrep.cpp~2106eb0a6bf2a1b5: Auto merged mysql-test/r/alter_table.result: Auto merged mysql-test/r/grant.result: Auto merged mysql-test/r/ps_6bdb.result: Auto merged mysql-test/r/ps_7ndb.result: Auto merged mysys/Makefile.am: Auto merged scripts/make_win_src_distribution.sh: Auto merged sql/field.cc: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_heap.h: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item.cc: Auto merged sql/item_subselect.cc: Auto merged sql/lex.h: Auto merged sql/lock.cc: Auto merged sql/log_event.cc: Auto merged sql/mysqld.cc: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/sp.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_handler.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.cc: Auto merged sql/table.h: Auto merged storage/heap/hp_delete.c: Auto merged storage/innobase/btr/btr0pcur.c: Auto merged storage/innobase/btr/btr0sea.c: Auto merged storage/innobase/include/read0read.h: Auto merged storage/innobase/include/srv0srv.h: Auto merged storage/innobase/include/trx0trx.h: Auto merged storage/innobase/include/univ.i: Auto merged storage/innobase/lock/lock0lock.c: Auto merged storage/innobase/read/read0read.c: Auto merged storage/innobase/row/row0ins.c: Auto merged storage/innobase/row/row0sel.c: Auto merged storage/innobase/row/row0umod.c: Auto merged storage/innobase/row/row0upd.c: Auto merged storage/innobase/srv/srv0srv.c: Auto merged storage/innobase/srv/srv0start.c: Auto merged storage/innobase/trx/trx0trx.c: Auto merged storage/myisam/ft_boolean_search.c: Auto merged storage/myisam/myisampack.c: Auto merged storage/myisammrg/myrg_static.c: Auto merged storage/ndb/include/kernel/AttributeDescriptor.hpp: Auto merged storage/ndb/include/kernel/BlockNumbers.h: Auto merged storage/ndb/include/kernel/GlobalSignalNumbers.h: Auto merged storage/ndb/include/kernel/kernel_types.h: Auto merged storage/ndb/include/kernel/signaldata/AlterTable.hpp: Auto merged storage/ndb/include/ndbapi/NdbDictionary.hpp: Auto merged storage/ndb/include/portlib/NdbTCP.h: Auto merged storage/ndb/src/common/debugger/BlockNames.cpp: Auto merged storage/ndb/src/common/logger/LogHandler.cpp: Auto merged storage/ndb/src/common/portlib/NdbTCP.cpp: Auto merged storage/ndb/src/common/portlib/win32/NdbTCP.c: Auto merged storage/ndb/src/common/transporter/TransporterRegistry.cpp: Auto merged storage/ndb/src/kernel/Makefile.am: Auto merged storage/ndb/src/kernel/SimBlockList.cpp: Auto merged storage/ndb/src/kernel/blocks/Makefile.am: Auto merged storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/suma/Suma.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.hpp: Auto merged storage/ndb/src/mgmapi/mgmapi.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.cpp: Auto merged storage/ndb/src/ndbapi/DictCache.cpp: Auto merged storage/ndb/src/ndbapi/DictCache.hpp: Auto merged storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: Auto merged storage/ndb/src/ndbapi/TransporterFacade.cpp: Auto merged storage/ndb/tools/Makefile.am: Auto merged storage/ndb/tools/ndb_condig.cpp: Auto merged strings/ctype-big5.c: Auto merged strings/ctype-ucs2.c: Auto merged support-files/mysql.spec.sh: Auto merged VC++Files/sql/mysqld.dsp: Manual 5.0 - 5.1 merge configure.in: Manual 5.0 - 5.1 merge sql/mysql_priv.h: Manual 5.0 - 5.1 merge sql/share/errmsg.txt: Manual 5.0 - 5.1 merge sql/sql_base.cc: Manual 5.0 - 5.1 merge sql/sql_prepare.cc: Manual 5.0 - 5.1 merge storage/ndb/src/common/util/version.c: Manual 5.0 - 5.1 merge storage/ndb/src/kernel/blocks/dblqh/Makefile.am: Manual 5.0 - 5.1 merge
-rw-r--r--.bzrignore2
-rw-r--r--BUILD/Makefile.am1
-rwxr-xr-xBUILD/check-cpu6
-rw-r--r--BitKeeper/etc/config2
-rwxr-xr-xVC++Files/client/mysqlclient.vcproj3
-rwxr-xr-xVC++Files/mysql.sln1
-rw-r--r--VC++Files/sql/mysqld.dsp18
-rwxr-xr-xVC++Files/strings/strings.vcproj3
-rw-r--r--client/mysql.cc7
-rw-r--r--client/mysqlcheck.c11
-rw-r--r--client/mysqltest.c1
-rw-r--r--config/ac-macros/ha_ndbcluster.m417
-rw-r--r--config/ac-macros/yassl.m49
-rw-r--r--configure.in101
-rw-r--r--dbug/my_main.c2
-rw-r--r--extra/yassl/src/Makefile.am4
-rw-r--r--extra/yassl/taocrypt/src/Makefile.am4
-rw-r--r--include/config-netware.h3
-rw-r--r--include/m_ctype.h1
-rw-r--r--include/my_global.h18
-rw-r--r--include/my_list.h2
-rw-r--r--include/my_sys.h5
-rw-r--r--mysql-test/include/ps_conv.inc16
-rw-r--r--mysql-test/include/varchar.inc1
-rw-r--r--mysql-test/lib/init_db.sql2
-rw-r--r--mysql-test/lib/mtr_cases.pl27
-rw-r--r--mysql-test/lib/mtr_misc.pl9
-rw-r--r--mysql-test/lib/mtr_process.pl89
-rw-r--r--mysql-test/lib/mtr_report.pl10
-rw-r--r--mysql-test/lib/mtr_timer.pl127
-rwxr-xr-xmysql-test/mysql-test-run.pl61
-rw-r--r--mysql-test/r/alter_table.result4
-rw-r--r--mysql-test/r/bdb.result5
-rw-r--r--mysql-test/r/bigint.result9
-rwxr-xr-xmysql-test/r/ctype_cp932.result14
-rw-r--r--mysql-test/r/derived.result11
-rw-r--r--mysql-test/r/distinct.result48
-rw-r--r--mysql-test/r/errors.result9
-rw-r--r--mysql-test/r/flush.result21
-rw-r--r--mysql-test/r/fulltext.result16
-rw-r--r--mysql-test/r/fulltext_order_by.result22
-rw-r--r--mysql-test/r/func_date_add.result26
-rw-r--r--mysql-test/r/func_misc.result35
-rw-r--r--mysql-test/r/func_str.result117
-rw-r--r--mysql-test/r/func_system.result15
-rw-r--r--mysql-test/r/func_time.result56
-rw-r--r--mysql-test/r/grant.result3
-rw-r--r--mysql-test/r/grant2.result26
-rw-r--r--mysql-test/r/group_by.result7
-rw-r--r--mysql-test/r/heap.result7
-rw-r--r--mysql-test/r/information_schema.result65
-rw-r--r--mysql-test/r/innodb.result17
-rw-r--r--mysql-test/r/insert_select.result4
-rw-r--r--mysql-test/r/insert_update.result6
-rw-r--r--mysql-test/r/join.result77
-rw-r--r--mysql-test/r/join_crash.result15
-rw-r--r--mysql-test/r/join_nested.result132
-rw-r--r--mysql-test/r/join_outer.result56
-rw-r--r--mysql-test/r/key_cache.result6
-rw-r--r--mysql-test/r/metadata.result11
-rw-r--r--mysql-test/r/multi_update.result16
-rw-r--r--mysql-test/r/ndb_alter_table.result18
-rw-r--r--mysql-test/r/order_by.result25
-rw-r--r--mysql-test/r/ps_2myisam.result162
-rw-r--r--mysql-test/r/ps_3innodb.result162
-rw-r--r--mysql-test/r/ps_4heap.result162
-rw-r--r--mysql-test/r/ps_5merge.result324
-rw-r--r--mysql-test/r/ps_6bdb.result162
-rw-r--r--mysql-test/r/ps_7ndb.result162
-rw-r--r--mysql-test/r/query_cache.result6
-rw-r--r--mysql-test/r/query_cache_notembedded.result14
-rw-r--r--mysql-test/r/row.result8
-rw-r--r--mysql-test/r/rpl_delete_all.result2
-rw-r--r--mysql-test/r/rpl_drop_db.result35
-rw-r--r--mysql-test/r/rpl_insert_select.result17
-rw-r--r--mysql-test/r/rpl_openssl.result6
-rw-r--r--mysql-test/r/rpl_sp.result2
-rw-r--r--mysql-test/r/rpl_trigger.result108
-rw-r--r--mysql-test/r/select.result392
-rw-r--r--mysql-test/r/select_safe.result2
-rw-r--r--mysql-test/r/show_check.result45
-rw-r--r--mysql-test/r/sp-error.result34
-rw-r--r--mysql-test/r/sp-security.result15
-rw-r--r--mysql-test/r/sp-threads.result25
-rw-r--r--mysql-test/r/sp.result91
-rw-r--r--mysql-test/r/subselect.result156
-rw-r--r--mysql-test/r/subselect2.result2
-rw-r--r--mysql-test/r/trigger.result103
-rw-r--r--mysql-test/r/type_bit.result4
-rw-r--r--mysql-test/r/type_bit_innodb.result2
-rw-r--r--mysql-test/r/type_datetime.result23
-rw-r--r--mysql-test/r/type_ranges.result16
-rw-r--r--mysql-test/r/union.result2
-rw-r--r--mysql-test/r/view.result78
-rw-r--r--mysql-test/r/xa.result4
-rw-r--r--mysql-test/t/bdb.test1
-rw-r--r--mysql-test/t/bigint.test3
-rw-r--r--mysql-test/t/ctype_cp932.test21
-rw-r--r--mysql-test/t/derived.test11
-rw-r--r--mysql-test/t/distinct.test344
-rw-r--r--mysql-test/t/errors.test15
-rw-r--r--mysql-test/t/flush.test31
-rw-r--r--mysql-test/t/fulltext.test12
-rw-r--r--mysql-test/t/fulltext_order_by.test24
-rw-r--r--mysql-test/t/func_date_add.test23
-rw-r--r--mysql-test/t/func_misc.test32
-rw-r--r--mysql-test/t/func_str.test39
-rw-r--r--mysql-test/t/func_system.test12
-rw-r--r--mysql-test/t/func_time.test52
-rw-r--r--mysql-test/t/grant.test7
-rw-r--r--mysql-test/t/grant2.test38
-rw-r--r--mysql-test/t/group_by.test12
-rw-r--r--mysql-test/t/heap.test11
-rw-r--r--mysql-test/t/information_schema.test35
-rw-r--r--mysql-test/t/innodb.test15
-rw-r--r--mysql-test/t/insert_select.test4
-rw-r--r--mysql-test/t/insert_update.test14
-rw-r--r--mysql-test/t/join.test7
-rw-r--r--mysql-test/t/join_crash.test15
-rw-r--r--mysql-test/t/join_nested.test107
-rw-r--r--mysql-test/t/join_outer.test13
-rw-r--r--mysql-test/t/key_cache.test7
-rw-r--r--mysql-test/t/kill.test2
-rw-r--r--mysql-test/t/metadata.test12
-rw-r--r--mysql-test/t/ndb_alter_table.test26
-rw-r--r--mysql-test/t/ndb_config.test1
-rw-r--r--mysql-test/t/order_by.test13
-rw-r--r--mysql-test/t/query_cache_notembedded.test19
-rw-r--r--mysql-test/t/row.test6
-rw-r--r--mysql-test/t/rpl_delete_all.test2
-rw-r--r--mysql-test/t/rpl_drop_db.test56
-rw-r--r--mysql-test/t/rpl_insert_select.test19
-rw-r--r--mysql-test/t/rpl_openssl.test2
-rw-r--r--mysql-test/t/rpl_trigger.test118
-rw-r--r--mysql-test/t/select.test108
-rw-r--r--mysql-test/t/select_safe.test2
-rw-r--r--mysql-test/t/show_check.test23
-rw-r--r--mysql-test/t/sp-error.test39
-rw-r--r--mysql-test/t/sp-security.test42
-rw-r--r--mysql-test/t/sp-threads.test45
-rw-r--r--mysql-test/t/sp.test267
-rw-r--r--mysql-test/t/subselect.test100
-rw-r--r--mysql-test/t/trigger.test123
-rw-r--r--mysql-test/t/type_bit.test4
-rw-r--r--mysql-test/t/type_bit_innodb.test2
-rw-r--r--mysql-test/t/type_datetime.test21
-rw-r--r--mysql-test/t/type_ranges.test7
-rw-r--r--mysql-test/t/union.test2
-rw-r--r--mysql-test/t/view.test86
-rw-r--r--mysql-test/t/xa.test4
-rw-r--r--mysys/Makefile.am2
-rw-r--r--mysys/charset.c26
-rw-r--r--mysys/list.c2
-rw-r--r--mysys/mf_dirname.c33
-rw-r--r--mysys/mf_getdate.c2
-rw-r--r--mysys/mf_pack.c12
-rw-r--r--mysys/my_init.c2
-rw-r--r--mysys/thr_lock.c3
-rw-r--r--ndb/include/kernel/signaldata/ApiBroadcast.hpp31
-rw-r--r--ndb/src/kernel/vm/KeyDescriptor.hpp41
-rw-r--r--scripts/make_win_src_distribution.sh4
-rw-r--r--server-tools/instance-manager/IMService.cpp18
-rw-r--r--server-tools/instance-manager/instance.cc336
-rw-r--r--server-tools/instance-manager/instance.h4
-rw-r--r--server-tools/instance-manager/instance_options.cc2
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc15
-rw-r--r--server-tools/instance-manager/options.cc83
-rw-r--r--server-tools/instance-manager/options.h2
-rw-r--r--server-tools/instance-manager/protocol.cc2
-rw-r--r--server-tools/instance-manager/user_map.cc17
-rw-r--r--sql-common/client.c5
-rw-r--r--sql-common/my_time.c6
-rw-r--r--sql/examples/ha_example.cc2
-rw-r--r--sql/field_conv.cc5
-rw-r--r--sql/ha_berkeley.cc20
-rw-r--r--sql/ha_berkeley.h5
-rw-r--r--sql/ha_heap.h2
-rw-r--r--sql/ha_innodb.cc410
-rw-r--r--sql/ha_innodb.h1
-rw-r--r--sql/ha_ndbcluster.cc16
-rw-r--r--sql/handler.cc73
-rw-r--r--sql/handler.h9
-rw-r--r--sql/init.cc3
-rw-r--r--sql/item.cc62
-rw-r--r--sql/item.h43
-rw-r--r--sql/item_cmpfunc.cc31
-rw-r--r--sql/item_cmpfunc.h9
-rw-r--r--sql/item_create.cc6
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_func.cc89
-rw-r--r--sql/item_func.h17
-rw-r--r--sql/item_strfunc.cc17
-rw-r--r--sql/item_subselect.cc189
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/item_timefunc.cc81
-rw-r--r--sql/item_timefunc.h35
-rw-r--r--sql/lex.h3
-rw-r--r--sql/lock.cc6
-rw-r--r--sql/log_event.cc16
-rw-r--r--sql/log_event.h6
-rw-r--r--sql/mysql_priv.h69
-rw-r--r--sql/mysqld.cc27
-rw-r--r--sql/set_var.cc22
-rw-r--r--sql/share/Makefile.am2
-rw-r--r--sql/share/errmsg.txt29
-rw-r--r--sql/slave.cc4
-rw-r--r--sql/sp.cc168
-rw-r--r--sql/sp.h11
-rw-r--r--sql/sp_cache.cc224
-rw-r--r--sql/sp_cache.h101
-rw-r--r--sql/sp_head.cc652
-rw-r--r--sql/sp_head.h2
-rw-r--r--sql/sp_rcontext.cc10
-rw-r--r--sql/sp_rcontext.h8
-rw-r--r--sql/sql_acl.cc63
-rw-r--r--sql/sql_base.cc1977
-rw-r--r--sql/sql_cache.cc10
-rw-r--r--sql/sql_class.cc225
-rw-r--r--sql/sql_class.h106
-rw-r--r--sql/sql_db.cc139
-rw-r--r--sql/sql_delete.cc11
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_handler.cc2
-rw-r--r--sql/sql_help.cc32
-rw-r--r--sql/sql_insert.cc191
-rw-r--r--sql/sql_lex.cc25
-rw-r--r--sql/sql_lex.h49
-rw-r--r--sql/sql_list.h7
-rw-r--r--sql/sql_load.cc1
-rw-r--r--sql/sql_olap.cc2
-rw-r--r--sql/sql_parse.cc531
-rw-r--r--sql/sql_prepare.cc33
-rw-r--r--sql/sql_select.cc48
-rw-r--r--sql/sql_select.h14
-rw-r--r--sql/sql_show.cc484
-rw-r--r--sql/sql_table.cc3
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_trigger.cc36
-rw-r--r--sql/sql_trigger.h51
-rw-r--r--sql/sql_union.cc20
-rw-r--r--sql/sql_update.cc17
-rw-r--r--sql/sql_view.cc110
-rw-r--r--sql/sql_view.h2
-rw-r--r--sql/sql_yacc.yy249
-rw-r--r--sql/table.cc475
-rw-r--r--sql/table.h212
-rw-r--r--storage/heap/hp_delete.c2
-rw-r--r--storage/innobase/btr/btr0pcur.c2
-rw-r--r--storage/innobase/btr/btr0sea.c7
-rw-r--r--storage/innobase/include/read0read.h3
-rw-r--r--storage/innobase/include/srv0srv.h1
-rw-r--r--storage/innobase/include/trx0trx.h15
-rw-r--r--storage/innobase/include/univ.i2
-rw-r--r--storage/innobase/lock/lock0lock.c8
-rw-r--r--storage/innobase/read/read0read.c17
-rw-r--r--storage/innobase/row/row0ins.c6
-rw-r--r--storage/innobase/row/row0sel.c23
-rw-r--r--storage/innobase/row/row0umod.c2
-rw-r--r--storage/innobase/row/row0upd.c2
-rw-r--r--storage/innobase/srv/srv0srv.c3
-rw-r--r--storage/innobase/srv/srv0start.c3
-rw-r--r--storage/innobase/trx/trx0trx.c25
-rw-r--r--storage/myisam/ft_boolean_search.c1
-rw-r--r--storage/myisam/myisampack.c8
-rw-r--r--storage/ndb/include/kernel/AttributeDescriptor.hpp3
-rw-r--r--storage/ndb/include/kernel/BlockNumbers.h4
-rw-r--r--storage/ndb/include/kernel/GlobalSignalNumbers.h4
-rw-r--r--storage/ndb/include/kernel/kernel_types.h7
-rw-r--r--storage/ndb/include/kernel/signaldata/AlterTable.hpp25
-rw-r--r--storage/ndb/include/ndbapi/NdbDictionary.hpp5
-rw-r--r--storage/ndb/include/portlib/NdbTCP.h2
-rw-r--r--storage/ndb/src/common/debugger/BlockNames.cpp1
-rw-r--r--storage/ndb/src/common/logger/LogHandler.cpp2
-rw-r--r--storage/ndb/src/common/portlib/NdbTCP.cpp15
-rw-r--r--storage/ndb/src/common/portlib/win32/NdbTCP.c32
-rw-r--r--storage/ndb/src/common/transporter/TransporterRegistry.cpp8
-rw-r--r--storage/ndb/src/common/util/version.c9
-rw-r--r--storage/ndb/src/kernel/Makefile.am2
-rw-r--r--storage/ndb/src/kernel/SimBlockList.cpp6
-rw-r--r--storage/ndb/src/kernel/blocks/Makefile.am1
-rw-r--r--storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp1
-rw-r--r--storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp8
-rw-r--r--storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp1
-rw-r--r--storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp129
-rw-r--r--storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp157
-rw-r--r--storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp1
-rw-r--r--storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp3
-rw-r--r--storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp2
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp2
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp68
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/Makefile.am8
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile9
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp4
-rw-r--r--storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp8
-rw-r--r--storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp149
-rw-r--r--storage/ndb/src/kernel/blocks/grep/Grep.cpp2010
-rw-r--r--storage/ndb/src/kernel/blocks/grep/Grep.hpp535
-rw-r--r--storage/ndb/src/kernel/blocks/grep/GrepInit.cpp164
-rw-r--r--storage/ndb/src/kernel/blocks/grep/Makefile.am23
-rw-r--r--storage/ndb/src/kernel/blocks/grep/systab_test/Makefile12
-rw-r--r--storage/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp138
-rw-r--r--storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp7
-rw-r--r--storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp1
-rw-r--r--storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp3
-rw-r--r--storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp38
-rw-r--r--storage/ndb/src/kernel/blocks/suma/Suma.cpp20
-rw-r--r--storage/ndb/src/kernel/vm/SimulatedBlock.cpp115
-rw-r--r--storage/ndb/src/kernel/vm/SimulatedBlock.hpp20
-rw-r--r--storage/ndb/src/mgmapi/mgmapi.cpp33
-rw-r--r--storage/ndb/src/mgmsrv/MgmtSrvr.cpp39
-rw-r--r--storage/ndb/src/ndbapi/DictCache.cpp72
-rw-r--r--storage/ndb/src/ndbapi/DictCache.hpp3
-rw-r--r--storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp23
-rw-r--r--storage/ndb/src/ndbapi/TransporterFacade.cpp12
-rw-r--r--storage/ndb/test/ndbapi/testGrep.cpp540
-rw-r--r--strings/Makefile.am4
-rw-r--r--strings/ctype-big5.c2
-rw-r--r--strings/ctype-bin.c1
-rw-r--r--strings/ctype-cp932.c2
-rw-r--r--strings/ctype-czech.c1
-rw-r--r--strings/ctype-euc_kr.c2
-rw-r--r--strings/ctype-eucjpms.c2
-rw-r--r--strings/ctype-extra.c1
-rw-r--r--strings/ctype-gb2312.c2
-rw-r--r--strings/ctype-gbk.c2
-rw-r--r--strings/ctype-latin1.c3
-rw-r--r--strings/ctype-sjis.c2
-rw-r--r--strings/ctype-tis620.c2
-rw-r--r--strings/ctype-uca.c34
-rw-r--r--strings/ctype-ucs2.c2
-rw-r--r--strings/ctype-ujis.c2
-rw-r--r--strings/ctype-utf8.c3
-rw-r--r--strings/ctype-win1250ch.c1
-rw-r--r--strings/longlong2str-x86.s35
-rw-r--r--strings/longlong2str_asm.c33
-rw-r--r--strings/my_strtoll10-x86.s62
-rw-r--r--support-files/MacOSX/Info.plist.sh6
-rw-r--r--support-files/MacOSX/Makefile.am15
-rw-r--r--support-files/MacOSX/postflight.sh (renamed from support-files/MacOSX/postinstall.sh)2
-rw-r--r--support-files/MacOSX/preflight.sh (renamed from support-files/MacOSX/preinstall.sh)4
-rw-r--r--support-files/Makefile.am3
-rw-r--r--support-files/mysql.spec.sh4
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/fork_big2.pl2
-rw-r--r--tests/mysql_client_test.c367
346 files changed, 11186 insertions, 8153 deletions
diff --git a/.bzrignore b/.bzrignore
index 2c20c4daf22..10bfea9154d 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1036,7 +1036,9 @@ support-files/MacOSX/Description.plist
support-files/MacOSX/Info.plist
support-files/MacOSX/ReadMe.txt
support-files/MacOSX/StartupParameters.plist
+support-files/MacOSX/postflight
support-files/MacOSX/postinstall
+support-files/MacOSX/preflight
support-files/MacOSX/preinstall
support-files/binary-configure
support-files/my-huge.cnf
diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am
index 27a42cdca16..45c1aaa1a76 100644
--- a/BUILD/Makefile.am
+++ b/BUILD/Makefile.am
@@ -19,6 +19,7 @@
EXTRA_DIST = FINISH.sh \
SETUP.sh \
+ autorun.sh \
check-cpu \
compile-alpha \
compile-alpha-ccc \
diff --git a/BUILD/check-cpu b/BUILD/check-cpu
index b970a4b9a5b..dc894c91cbd 100755
--- a/BUILD/check-cpu
+++ b/BUILD/check-cpu
@@ -90,6 +90,9 @@ case "$cpu_family--$model_name" in
*Athlon*)
cpu_arg="athlon";
;;
+ *Opteron*)
+ cpu_arg="opteron";
+ ;;
# Intel ia64
*Itanium*)
@@ -147,6 +150,9 @@ case "$cc_ver--$cc_verno" in
ppc-*)
check_cpu_args='-mcpu=$cpu_arg -mtune=$cpu_arg'
;;
+ x86_64-*)
+ check_cpu_args='-mtune=$cpu_arg'
+ ;;
*)
check_cpu_cflags=""
return
diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config
index 9e69034d89d..cc6dbacce10 100644
--- a/BitKeeper/etc/config
+++ b/BitKeeper/etc/config
@@ -71,6 +71,8 @@ hours:
[arjen:]checkout:get
[kostja:]checkout:get
[nick:]checkout:get
+[jonas:]checkout:get
+[tomas:]checkout:get
checkout:edit
eoln:unix
diff --git a/VC++Files/client/mysqlclient.vcproj b/VC++Files/client/mysqlclient.vcproj
index 8e01db86c70..eebba9ebe0e 100755
--- a/VC++Files/client/mysqlclient.vcproj
+++ b/VC++Files/client/mysqlclient.vcproj
@@ -2731,6 +2731,9 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\strings\str_alloc.c">
+ </File>
+ <File
RelativePath="..\strings\strcend.c">
<FileConfiguration
Name="Release|Win32">
diff --git a/VC++Files/mysql.sln b/VC++Files/mysql.sln
index c7378231ae6..fc75dc24723 100755
--- a/VC++Files/mysql.sln
+++ b/VC++Files/mysql.sln
@@ -24,6 +24,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "innobase", "innobase\innoba
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmysql", "libmysql\libmysql.vcproj", "{1FC6EB72-1D0F-4E40-8851-1CC5DEB94F0F}"
ProjectSection(ProjectDependencies) = postProject
+ {EEC1300B-85A5-497C-B3E1-F708021DF859} = {EEC1300B-85A5-497C-B3E1-F708021DF859}
{BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} = {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}
{8762A9B8-72A9-462E-A9A2-F3265081F8AF} = {8762A9B8-72A9-462E-A9A2-F3265081F8AF}
{44D9C7DC-6636-4B82-BD01-6876C64017DF} = {44D9C7DC-6636-4B82-BD01-6876C64017DF}
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
index e2832c98434..3957f92f364 100644
--- a/VC++Files/sql/mysqld.dsp
+++ b/VC++Files/sql/mysqld.dsp
@@ -49,7 +49,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../zlib" /I "../include" /I "../regex" /I "../extra/yassl/include" /D "NDEBUG" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../zlib" /I "../include" /I "../regex" /I "../extra/yassl/include" /D "NDEBUG" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x410 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -75,7 +75,7 @@ LINK32=xilink6.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../storage/bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_FEDERATED_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c
+# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_FEDERATED_DB" /D "HAVE_EXAMPLE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c
# SUBTRACT CPP /Fr /YX
# ADD BASE RSC /l 0x410 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -102,7 +102,7 @@ LINK32=xilink6.exe
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G5 /MT /W3 /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D "DBUG_OFF" /FD /c
# SUBTRACT BASE CPP /YX
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "__NT__" /D "DBUG_OFF" /D "NDEBUG" /D "HAVE_INNOBASE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "__NT__" /D "DBUG_OFF" /D "NDEBUG" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x410 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -130,7 +130,7 @@ LINK32=xilink6.exe
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT BASE CPP /YX
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../storage/bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_FEDERATED_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt-max /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_EXAMPLE_DB" /D "HAVE_FEDERATED_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-nt-max /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -159,7 +159,7 @@ LINK32=xilink6.exe
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT BASE CPP /YX
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../storage/bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "NDEBUG" /D "DBUG_OFF" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_FEDERATED_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-max /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../bdb/build_win32" /I "../include" /I "../regex" /I "../extra/yassl/include" /I "../zlib" /D "NDEBUG" /D "DBUG_OFF" /D "USE_SYMDIR" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "HAVE_ARCHIVE_DB" /D "HAVE_BLACKHOLE_DB" /D "HAVE_EXAMPLE_DB" /D "HAVE_FEDERATED_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-max /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -215,7 +215,7 @@ LINK32=xilink6.exe
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_DLOPEN" /D "NDEBUG" /FD /c
# SUBTRACT BASE CPP /YX
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /D MYSQL_SERVER_SUFFIX=-pro /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /D MYSQL_SERVER_SUFFIX=-pro /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -272,7 +272,7 @@ LINK32=xilink6.exe
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "USE_SYMDIR" /D "HAVE_DLOPEN" /D "NDEBUG" /FD /c
# SUBTRACT BASE CPP /YX
-# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "__NT__" /D "DBUG_OFF" /D "NDEBUG" /D "HAVE_INNOBASE_DB" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-pro-nt /FD /c
+# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../zlib" /I "../extra/yassl/include" /D "__NT__" /D "DBUG_OFF" /D "NDEBUG" /D "HAVE_INNOBASE_DB" /D "HAVE_ARCHIVE_DB" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /D MYSQL_SERVER_SUFFIX=-pro-nt /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -460,6 +460,10 @@ SOURCE=.\examples\ha_archive.cpp
# End Source File
# Begin Source File
+SOURCE=.\examples\ha_example.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\ha_blackhole.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/strings/strings.vcproj b/VC++Files/strings/strings.vcproj
index 42099bd79ed..8e16a0c7221 100755
--- a/VC++Files/strings/strings.vcproj
+++ b/VC++Files/strings/strings.vcproj
@@ -760,6 +760,9 @@
</FileConfiguration>
</File>
<File
+ RelativePath=".\str_alloc.c">
+ </File>
+ <File
RelativePath="strcend.c">
<FileConfiguration
Name="Release|Win32">
diff --git a/client/mysql.cc b/client/mysql.cc
index b8655d7c5f5..04b634a47af 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -624,7 +624,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
(gptr*) &current_prompt, (gptr*) &current_prompt, 0, GET_STR_ALLOC,
@@ -1598,11 +1598,8 @@ You can turn off this feature to get a quicker startup with -A\n\n");
mysql_free_result(fields);
}
else
- {
- tee_fprintf(stdout,
- "Didn't find any fields in table '%s'\n",table_row[0]);
field_names[i]= 0;
- }
+
i++;
}
mysql_free_result(tables);
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index c767f1c89b7..465213cce50 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -575,8 +575,13 @@ static void print_result()
if (status)
{
+ /*
+ if there was an error with the table, we have --auto-repair set,
+ and this isn't a repair op, then add the table to the tables4repair
+ list
+ */
if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
- (!opt_fast || strcmp(row[3],"OK")))
+ strcmp(row[3],"OK"))
insert_dynamic(&tables4repair, prev);
found_error=0;
if (opt_silent)
@@ -595,8 +600,8 @@ static void print_result()
strmov(prev, row[0]);
putchar('\n');
}
- if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
- !opt_fast)
+ /* add the last table to be repaired to the list */
+ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR)
insert_dynamic(&tables4repair, prev);
mysql_free_result(res);
}
diff --git a/client/mysqltest.c b/client/mysqltest.c
index ca4d9319707..57b81e46b66 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -2781,6 +2781,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
if (!disable_result_log)
{
ulong affected_rows; /* Ok to be undef if 'disable_info' is set */
+ LINT_INIT(affected_rows);
if (res)
{
diff --git a/config/ac-macros/ha_ndbcluster.m4 b/config/ac-macros/ha_ndbcluster.m4
index 28b41b522fc..356108ad9ea 100644
--- a/config/ac-macros/ha_ndbcluster.m4
+++ b/config/ac-macros/ha_ndbcluster.m4
@@ -62,10 +62,19 @@ AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [
[ndb_debug="$withval"],
[ndb_debug="default"])
AC_ARG_WITH([ndb-ccflags],
- [
- --with-ndb-ccflags Extra CC options for ndb compile],
- [ndb_cxxflags_fix="$ndb_cxxflags_fix $withval"],
- [ndb_cxxflags_fix=$ndb_cxxflags_fix])
+ AC_HELP_STRING([--with-ndb-ccflags=CFLAGS],
+ [Extra CFLAGS for ndb compile]),
+ [ndb_ccflags=${withval}],
+ [ndb_ccflags=""])
+
+ case "$ndb_ccflags" in
+ "yes")
+ AC_MSG_RESULT([The --ndb-ccflags option requires a parameter (passed to CC for ndb compilation)])
+ ;;
+ *)
+ ndb_cxxflags_fix="$ndb_cxxflags_fix $ndb_ccflags"
+ ;;
+ esac
AC_MSG_CHECKING([for NDB Cluster options])
AC_MSG_RESULT([])
diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4
index fb7c89181df..92133339343 100644
--- a/config/ac-macros/yassl.m4
+++ b/config/ac-macros/yassl.m4
@@ -5,12 +5,9 @@ extra/yassl/src/Makefile)
AC_DEFUN([MYSQL_CHECK_YASSL], [
AC_MSG_CHECKING(for yaSSL)
- AC_ARG_WITH([yassl],
- [ --with-yassl Include the yaSSL support],
- [yassl=yes],
- [yassl=no])
+ AC_ARG_WITH([yassl], [ --with-yassl Include the yaSSL support],,)
- if test "$yassl" = "yes"
+ if test "$with_yassl" = "yes"
then
if test "$openssl" != "no"
then
@@ -30,5 +27,5 @@ AC_DEFUN([MYSQL_CHECK_YASSL], [
AC_SUBST(openssl_libs)
AC_SUBST(openssl_includes)
AC_SUBST(yassl_dir)
- AM_CONDITIONAL([HAVE_YASSL], [ test "$yassl" = "yes" ])
+ AM_CONDITIONAL([HAVE_YASSL], [ test "with_yassl" = "yes" ])
])
diff --git a/configure.in b/configure.in
index 512b8bb876e..0ae78d76d9a 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
dnl -*- ksh -*-
dnl Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.57)dnl Minimum Autoconf version required.
+AC_PREREQ(2.52)dnl Minimum Autoconf version required.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
@@ -131,6 +131,7 @@ AC_PROG_MAKE_SET
# Hack for OS X/Darwin and Metrowerks CodeWarrior
AC_ARG_WITH(darwin-mwcc,
[ --with-darwin-mwcc Use Metrowerks CodeWarrior wrappers on OS X/Darwin],[
+ if [ "with_darwin_mwcc" = yes ] ; then
builddir=`pwd`
ccwrapper="$builddir/support-files/MacOSX/mwcc-wrapper"
arwrapper="$builddir/support-files/MacOSX/mwar-wrapper"
@@ -142,7 +143,7 @@ AC_ARG_WITH(darwin-mwcc,
export CC CXX LD AR RANLIB
AC_SUBST(AR)
AC_SUBST(RANLIB)
- with_darwin_mwcc=yes
+ fi
])
AM_CONDITIONAL(DARWIN_MWCC, test x$with_darwin_mwcc = xyes)
@@ -2446,7 +2447,7 @@ thread_dirs=
dnl This probably should be cleaned up more - for now the threaded
dnl client is just using plain-old libs.
-sql_client_dirs="libmysql strings regex client"
+sql_client_dirs="strings regex mysys sql/share libmysql client"
linked_client_targets="linked_libmysql_sources"
if test "$THREAD_SAFE_CLIENT" != "no"
@@ -2484,7 +2485,7 @@ then
AC_DEFINE([THREAD], [1],
[Define if you want to have threaded code. This may be undef on client code])
# Avoid _PROGRAMS names
- THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o"
+ THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o"
AC_SUBST(THREAD_LOBJECTS)
server_scripts="mysqld_safe mysql_install_db"
sql_server_dirs="strings mysys dbug extra regex"
@@ -2597,7 +2598,6 @@ esac
# END of configuration for optional table handlers
#
sql_server_dirs="$sql_server_dirs storage/myisam storage/myisammrg storage/heap vio sql"
-
fi
# IMPORTANT - do not modify LIBS past this line - this hack is the only way
@@ -2729,53 +2729,50 @@ AC_SUBST([NDB_SIZEOF_INT])
AC_SUBST([NDB_SIZEOF_LONG])
AC_SUBST([NDB_SIZEOF_LONG_LONG])
-AC_CONFIG_FILES(storage/ndb/Makefile storage/ndb/include/Makefile dnl
- storage/ndb/src/Makefile storage/ndb/src/common/Makefile dnl
- storage/ndb/docs/Makefile dnl
- storage/ndb/tools/Makefile dnl
- storage/ndb/src/common/debugger/Makefile dnl
- storage/ndb/src/common/debugger/signaldata/Makefile dnl
- storage/ndb/src/common/portlib/Makefile dnl
- storage/ndb/src/common/util/Makefile dnl
- storage/ndb/src/common/logger/Makefile dnl
- storage/ndb/src/common/transporter/Makefile dnl
- storage/ndb/src/common/mgmcommon/Makefile dnl
- storage/ndb/src/kernel/Makefile dnl
- storage/ndb/src/kernel/error/Makefile dnl
- storage/ndb/src/kernel/blocks/Makefile dnl
- storage/ndb/src/kernel/blocks/cmvmi/Makefile dnl
- storage/ndb/src/kernel/blocks/dbacc/Makefile dnl
- storage/ndb/src/kernel/blocks/dbdict/Makefile dnl
- storage/ndb/src/kernel/blocks/dbdih/Makefile dnl
- storage/ndb/src/kernel/blocks/dblqh/Makefile dnl
- storage/ndb/src/kernel/blocks/dbtc/Makefile dnl
- storage/ndb/src/kernel/blocks/dbtup/Makefile dnl
- storage/ndb/src/kernel/blocks/ndbfs/Makefile dnl
- storage/ndb/src/kernel/blocks/ndbcntr/Makefile dnl
- storage/ndb/src/kernel/blocks/qmgr/Makefile dnl
- storage/ndb/src/kernel/blocks/trix/Makefile dnl
- storage/ndb/src/kernel/blocks/backup/Makefile dnl
- storage/ndb/src/kernel/blocks/dbutil/Makefile dnl
- storage/ndb/src/kernel/blocks/suma/Makefile dnl
- storage/ndb/src/kernel/blocks/grep/Makefile dnl
- storage/ndb/src/kernel/blocks/dbtux/Makefile dnl
- storage/ndb/src/kernel/vm/Makefile dnl
- storage/ndb/src/mgmapi/Makefile dnl
- storage/ndb/src/ndbapi/Makefile dnl
- storage/ndb/src/mgmsrv/Makefile dnl
- storage/ndb/src/mgmclient/Makefile dnl
- storage/ndb/src/cw/Makefile dnl
- storage/ndb/src/cw/cpcd/Makefile dnl
- storage/ndb/test/Makefile dnl
- storage/ndb/test/src/Makefile dnl
- storage/ndb/test/ndbapi/Makefile dnl
- storage/ndb/test/ndbapi/bank/Makefile dnl
- storage/ndb/test/tools/Makefile dnl
- storage/ndb/test/run-test/Makefile dnl
- storage/ndb/include/ndb_version.h dnl
- storage/ndb/include/ndb_global.h dnl
- storage/ndb/include/ndb_types.h dnl
- mysql-test/ndb/Makefile dnl
+AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl
+ ndb/src/Makefile ndb/src/common/Makefile dnl
+ ndb/docs/Makefile dnl
+ ndb/tools/Makefile dnl
+ ndb/src/common/debugger/Makefile dnl
+ ndb/src/common/debugger/signaldata/Makefile dnl
+ ndb/src/common/portlib/Makefile dnl
+ ndb/src/common/util/Makefile dnl
+ ndb/src/common/logger/Makefile dnl
+ ndb/src/common/transporter/Makefile dnl
+ ndb/src/common/mgmcommon/Makefile dnl
+ ndb/src/kernel/Makefile dnl
+ ndb/src/kernel/error/Makefile dnl
+ ndb/src/kernel/blocks/Makefile dnl
+ ndb/src/kernel/blocks/cmvmi/Makefile dnl
+ ndb/src/kernel/blocks/dbacc/Makefile dnl
+ ndb/src/kernel/blocks/dbdict/Makefile dnl
+ ndb/src/kernel/blocks/dbdih/Makefile dnl
+ ndb/src/kernel/blocks/dblqh/Makefile dnl
+ ndb/src/kernel/blocks/dbtc/Makefile dnl
+ ndb/src/kernel/blocks/dbtup/Makefile dnl
+ ndb/src/kernel/blocks/ndbfs/Makefile dnl
+ ndb/src/kernel/blocks/ndbcntr/Makefile dnl
+ ndb/src/kernel/blocks/qmgr/Makefile dnl
+ ndb/src/kernel/blocks/trix/Makefile dnl
+ ndb/src/kernel/blocks/backup/Makefile dnl
+ ndb/src/kernel/blocks/dbutil/Makefile dnl
+ ndb/src/kernel/blocks/suma/Makefile dnl
+ ndb/src/kernel/blocks/dbtux/Makefile dnl
+ ndb/src/kernel/vm/Makefile dnl
+ ndb/src/mgmapi/Makefile dnl
+ ndb/src/ndbapi/Makefile dnl
+ ndb/src/mgmsrv/Makefile dnl
+ ndb/src/mgmclient/Makefile dnl
+ ndb/src/cw/Makefile dnl
+ ndb/src/cw/cpcd/Makefile dnl
+ ndb/test/Makefile dnl
+ ndb/test/src/Makefile dnl
+ ndb/test/ndbapi/Makefile dnl
+ ndb/test/ndbapi/bank/Makefile dnl
+ ndb/test/tools/Makefile dnl
+ ndb/test/run-test/Makefile mysql-test/ndb/Makefile dnl
+ ndb/include/ndb_version.h ndb/include/ndb_global.h dnl
+ ndb/include/ndb_types.h dnl
)
fi
diff --git a/dbug/my_main.c b/dbug/my_main.c
index 90af23b42b9..ed1c9329235 100644
--- a/dbug/my_main.c
+++ b/dbug/my_main.c
@@ -18,7 +18,9 @@ char *argv[];
#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
pthread_init(); /* Must be called before DBUG_ENTER */
#endif
+#ifdef THREAD
my_thread_global_init();
+#endif
{
DBUG_ENTER ("main");
DBUG_PROCESS (argv[0]);
diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am
index 4ebb9a2d862..83397e24168 100644
--- a/extra/yassl/src/Makefile.am
+++ b/extra/yassl/src/Makefile.am
@@ -1,7 +1,7 @@
INCLUDES = -I../include -I../taocrypt/include -I../mySTL
-noinst_LIBRARIES = libyassl.a
-libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \
+noinst_LTLIBRARIES = libyassl.la
+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 = ../include/*.hpp ../include/openssl/*.h
diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am
index 5bf45074a98..4549c218d87 100644
--- a/extra/yassl/taocrypt/src/Makefile.am
+++ b/extra/yassl/taocrypt/src/Makefile.am
@@ -1,7 +1,7 @@
INCLUDES = -I../include -I../../mySTL
-noinst_LIBRARIES = libtaocrypt.a
-libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \
+noinst_LTLIBRARIES = libtaocrypt.la
+libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \
coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp integer.cpp \
md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \
template_instnt.cpp
diff --git a/include/config-netware.h b/include/config-netware.h
index 16fa451a770..4c46ccd3ec7 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -53,6 +53,7 @@ extern "C" {
#define HAVE_PTHREAD_YIELD_ZERO_ARG 1
#define HAVE_BROKEN_REALPATH 1
+/* changes made to make use of LibC-June-2004 for building purpose */
#undef HAVE_POSIX_SIGNALS
#undef HAVE_PTHREAD_ATTR_SETSCOPE
#undef HAVE_ALLOC_A
@@ -62,6 +63,8 @@ extern "C" {
#undef HAVE_PTHREAD_SETSCHEDPARAM
#undef HAVE_READLINK
#undef HAVE_STPCPY
+/* changes end */
+
/* no libc crypt() function */
#ifdef HAVE_OPENSSL
#define HAVE_CRYPT 1
diff --git a/include/m_ctype.h b/include/m_ctype.h
index 8bb8e5c76df..e0a26c4ce56 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -231,6 +231,7 @@ typedef struct charset_info_st
uint mbmaxlen;
uint16 min_sort_char;
uint16 max_sort_char; /* For LIKE optimization */
+ my_bool escape_with_backslash_is_dangerous;
MY_CHARSET_HANDLER *cset;
MY_COLLATION_HANDLER *coll;
diff --git a/include/my_global.h b/include/my_global.h
index f81216e3add..97d896181e3 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -1015,7 +1015,17 @@ typedef char bool; /* Ordinary boolean values 0 1 */
#ifndef set_timespec
#ifdef HAVE_TIMESPEC_TS_SEC
-#define set_timespec(ABSTIME,SEC) { (ABSTIME).ts_sec=time(0) + (time_t) (SEC); (ABSTIME).ts_nsec=0; }
+#define set_timespec(ABSTIME,SEC) \
+{ \
+ (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \
+ (ABSTIME).ts_nsec=0; \
+}
+#define set_timespec_nsec(ABSTIME,NSEC) \
+{ \
+ ulonglong now= my_getsystime() + (NSEC/100); \
+ (ABSTIME).ts_sec= (now / ULL(10000000)); \
+ (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
+}
#else
#define set_timespec(ABSTIME,SEC) \
{\
@@ -1024,6 +1034,12 @@ typedef char bool; /* Ordinary boolean values 0 1 */
(ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\
(ABSTIME).tv_nsec=tv.tv_usec*1000;\
}
+#define set_timespec_nsec(ABSTIME,NSEC) \
+{\
+ ulonglong now= my_getsystime() + (NSEC/100); \
+ (ABSTIME).tv_sec= (now / ULL(10000000)); \
+ (ABSTIME).tv_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
+}
#endif /* HAVE_TIMESPEC_TS_SEC */
#endif /* set_timespec */
diff --git a/include/my_list.h b/include/my_list.h
index f786621e311..92598696fc4 100644
--- a/include/my_list.h
+++ b/include/my_list.h
@@ -36,7 +36,7 @@ extern void list_free(LIST *root,unsigned int free_data);
extern unsigned int list_length(LIST *);
extern int list_walk(LIST *,list_walk_action action,gptr argument);
-#define rest(a) ((a)->next)
+#define list_rest(a) ((a)->next)
#define list_push(a,b) (a)=list_cons((b),(a))
#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old) ; my_free((gptr) old,MYF(MY_FAE)); }
diff --git a/include/my_sys.h b/include/my_sys.h
index d5488ce12fa..11e8a36f5fa 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -866,6 +866,11 @@ extern void add_compiled_collation(CHARSET_INFO *cs);
extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
char *to, ulong to_length,
const char *from, ulong length);
+#ifdef __WIN__
+#define BACKSLASH_MBTAIL
+/* File system character set */
+extern CHARSET_INFO *fs_character_set(void);
+#endif
extern ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info,
char *to, ulong to_length,
const char *from, ulong length);
diff --git a/mysql-test/include/ps_conv.inc b/mysql-test/include/ps_conv.inc
index 0b6e27619e6..0dd819f6e62 100644
--- a/mysql-test/include/ps_conv.inc
+++ b/mysql-test/include/ps_conv.inc
@@ -576,15 +576,19 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
# Use the minimum BIGINT from the manual
#
@@ -592,15 +596,19 @@ set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
# Numeric overflow of columns(c1, c2, c3, c4, c5, c12) with type not in
@@ -610,8 +618,10 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
# Attention: The columns(c1,c2,c3,c4,c5,c6) do not get the overflow,
# because the string is treated as written integer and
@@ -620,15 +630,19 @@ set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
# Attention: The columns(c1,c2,c3,c4,c5,c6) do not get the overflow,
# because the string is treated as written integer and
@@ -637,8 +651,10 @@ set @arg00= '-1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
--vertical_results
+--replace_result e+0 e+
execute my_select ;
--horizontal_results
+--replace_result e+0 e+
execute my_delete ;
########################## test of string types ##########################
diff --git a/mysql-test/include/varchar.inc b/mysql-test/include/varchar.inc
index 13b4315f2b8..70b563e871c 100644
--- a/mysql-test/include/varchar.inc
+++ b/mysql-test/include/varchar.inc
@@ -229,6 +229,7 @@ drop table t1;
#
# Bug #9489: problem with hash indexes
+# Bug #10802: Index is not used if table using BDB engine on HP-UX
#
create table t1(a int, b varchar(12), key ba(b, a));
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql
index a71de229ee9..37353e5974f 100644
--- a/mysql-test/lib/init_db.sql
+++ b/mysql-test/lib/init_db.sql
@@ -518,7 +518,7 @@ CREATE TABLE proc (
security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL,
param_list blob DEFAULT '' NOT NULL,
returns char(64) DEFAULT '' NOT NULL,
- body blob DEFAULT '' NOT NULL,
+ body longblob DEFAULT '' NOT NULL,
definer char(77) collate utf8_bin DEFAULT '' NOT NULL,
created timestamp,
modified timestamp,
diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl
index 12714ddc1ad..158fd602ef8 100644
--- a/mysql-test/lib/mtr_cases.pl
+++ b/mysql-test/lib/mtr_cases.pl
@@ -53,21 +53,20 @@ sub collect_test_cases ($) {
else
{
# ----------------------------------------------------------------------
- # Skip some tests listed in disabled.def
+ # Disable some tests listed in disabled.def
# ----------------------------------------------------------------------
- my %skiplist;
- my $skipfile= "$testdir/disabled.def";
- if ( open(SKIPFILE, $skipfile) )
+ my %disabled;
+ if ( open(DISABLED, "$testdir/disabled.def" ) )
{
- while ( <SKIPFILE> )
+ while ( <DISABLED> )
{
chomp;
if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
{
- $skiplist{$1}= $2;
+ $disabled{$1}= $2;
}
}
- close SKIPFILE;
+ close DISABLED;
}
foreach my $elem ( sort readdir(TESTDIR) ) {
@@ -75,7 +74,7 @@ sub collect_test_cases ($) {
next if ! defined $tname;
next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test);
- collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%skiplist);
+ collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled);
}
closedir TESTDIR;
}
@@ -119,7 +118,7 @@ sub collect_one_test_case($$$$$$) {
my $tname= shift;
my $elem= shift;
my $cases= shift;
- my $skiplist=shift;
+ my $disabled=shift;
my $path= "$testdir/$elem";
@@ -188,7 +187,7 @@ sub collect_one_test_case($$$$$$) {
my $slave_mi_file= "$testdir/$tname.slave-mi";
my $master_sh= "$testdir/$tname-master.sh";
my $slave_sh= "$testdir/$tname-slave.sh";
- my $disabled= "$testdir/$tname.disabled";
+ my $disabled_file= "$testdir/$tname.disabled";
$tinfo->{'master_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : [];
$tinfo->{'slave_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : [];
@@ -292,18 +291,18 @@ sub collect_one_test_case($$$$$$) {
}
# FIXME why this late?
- if ( $skiplist->{$tname} )
+ if ( $disabled->{$tname} )
{
$tinfo->{'skip'}= 1;
$tinfo->{'disable'}= 1; # Sub type of 'skip'
- $tinfo->{'comment'}= $skiplist->{$tname} if $skiplist->{$tname};
+ $tinfo->{'comment'}= $disabled->{$tname} if $disabled->{$tname};
}
- if ( -f $disabled )
+ if ( -f $disabled_file )
{
$tinfo->{'skip'}= 1;
$tinfo->{'disable'}= 1; # Sub type of 'skip'
- $tinfo->{'comment'}= mtr_fromfile($disabled);
+ $tinfo->{'comment'}= mtr_fromfile($disabled_file);
}
# We can't restart a running server that may be in use
diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl
index c1aab340a16..9a12d842998 100644
--- a/mysql-test/lib/mtr_misc.pl
+++ b/mysql-test/lib/mtr_misc.pl
@@ -7,6 +7,7 @@
use strict;
sub mtr_full_hostname ();
+sub mtr_short_hostname ();
sub mtr_init_args ($);
sub mtr_add_arg ($$);
sub mtr_path_exists(@);
@@ -21,6 +22,7 @@ sub mtr_exe_exists(@);
# We want the fully qualified host name and hostname() may have returned
# only the short name. So we use the resolver to find out.
+# Note that this might fail on some platforms
sub mtr_full_hostname () {
@@ -35,6 +37,13 @@ sub mtr_full_hostname () {
return $hostname;
}
+sub mtr_short_hostname () {
+
+ my $hostname= hostname();
+ $hostname =~ s/\..+$//;
+ return $hostname;
+}
+
# FIXME move to own lib
sub mtr_init_args ($) {
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index 1eb4f6b7c58..c9ae92305c2 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -185,10 +185,6 @@ sub spawn_parent_impl {
if ( $mode eq 'run' or $mode eq 'test' )
{
- my $exit_value= -1;
- my $signal_num= 0;
- my $dumped_core= 0;
-
if ( $mode eq 'run' )
{
# Simple run of command, we wait for it to return
@@ -199,11 +195,7 @@ sub spawn_parent_impl {
mtr_error("$path ($pid) got lost somehow");
}
- $exit_value= $? >> 8;
- $signal_num= $? & 127;
- $dumped_core= $? & 128;
-
- return $exit_value;
+ return mtr_process_exit_status($?);
}
else
{
@@ -217,6 +209,8 @@ sub spawn_parent_impl {
# FIXME is this as it should be? Can't mysqld terminate
# normally from running a test case?
+ my $exit_value= -1;
+ my $saved_exit_value;
my $ret_pid; # What waitpid() returns
while ( ($ret_pid= waitpid(-1,0)) != -1 )
@@ -226,12 +220,28 @@ sub spawn_parent_impl {
# but not $exit_value, this is flagged from
#
+ my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid);
+ if ( $timer_name )
+ {
+ if ( $timer_name eq "suite" )
+ {
+ # We give up here
+ # FIXME we should only give up the suite, not all of the run?
+ print STDERR "\n";
+ mtr_error("Test suite timeout");
+ }
+ elsif ( $timer_name eq "testcase" )
+ {
+ $saved_exit_value= 63; # Mark as timeout
+ kill(9, $pid); # Kill mysqltest
+ next; # Go on and catch the termination
+ }
+ }
+
if ( $ret_pid == $pid )
{
# We got termination of mysqltest, we are done
- $exit_value= $? >> 8;
- $signal_num= $? & 127;
- $dumped_core= $? & 128;
+ $exit_value= mtr_process_exit_status($?);
last;
}
@@ -279,7 +289,7 @@ sub spawn_parent_impl {
}
}
- return $exit_value;
+ return $saved_exit_value || $exit_value;
}
}
else
@@ -290,6 +300,23 @@ sub spawn_parent_impl {
}
+# ----------------------------------------------------------------------
+# We try to emulate how an Unix shell calculates the exit code
+# ----------------------------------------------------------------------
+
+sub mtr_process_exit_status {
+ my $raw_status= shift;
+
+ if ( $raw_status & 127 )
+ {
+ return ($raw_status & 127) + 128; # Signal num + 128
+ }
+ else
+ {
+ return $raw_status >> 8; # Exit code
+ }
+}
+
##############################################################################
#
@@ -329,7 +356,7 @@ sub mtr_kill_leftovers () {
});
}
- mtr_mysqladmin_shutdown(\@args);
+ mtr_mysqladmin_shutdown(\@args, 20);
# We now have tried to terminate nice. We have waited for the listen
# port to be free, but can't really tell if the mysqld process died
@@ -439,7 +466,8 @@ sub mtr_stop_mysqld_servers ($) {
# First try nice normal shutdown using 'mysqladmin'
# ----------------------------------------------------------------------
- mtr_mysqladmin_shutdown($spec);
+ # Shutdown time must be high as slave may be in reconnect
+ mtr_mysqladmin_shutdown($spec, 70);
# ----------------------------------------------------------------------
# We loop with waitpid() nonblocking to see how many of the ones we
@@ -473,6 +501,7 @@ sub mtr_stop_mysqld_servers ($) {
}
else
{
+ # Server is dead, we remove the pidfile if any
# Race, could have been removed between I tested with -f
# and the unlink() below, so I better check again with -f
@@ -502,10 +531,12 @@ sub mtr_stop_mysqld_servers ($) {
# that for true Win32 processes, kill(0,$pid) will not return 1.
# ----------------------------------------------------------------------
+ start_reap_all(); # Avoid zombies
+
SIGNAL:
foreach my $sig (15,9)
{
- my $retries= 10; # 10 seconds
+ my $retries= 20; # FIXME 20 seconds, this is silly!
kill($sig, keys %mysqld_pids);
while ( $retries-- and kill(0, keys %mysqld_pids) )
{
@@ -514,6 +545,8 @@ sub mtr_stop_mysqld_servers ($) {
}
}
+ stop_reap_all(); # Get into control again
+
# ----------------------------------------------------------------------
# Now, we check if all we can find using kill(0,$pid) are dead,
# and just assume the rest are. We cleanup socket and PID files.
@@ -584,8 +617,9 @@ sub mtr_stop_mysqld_servers ($) {
#
##############################################################################
-sub mtr_mysqladmin_shutdown () {
+sub mtr_mysqladmin_shutdown {
my $spec= shift;
+ my $adm_shutdown_tmo= shift;
my %mysql_admin_pids;
my @to_kill_specs;
@@ -624,7 +658,7 @@ sub mtr_mysqladmin_shutdown () {
mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket
}
mtr_add_arg($args, "--connect_timeout=5");
- mtr_add_arg($args, "--shutdown_timeout=20");
+ mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo");
mtr_add_arg($args, "shutdown");
# We don't wait for termination of mysqladmin
my $pid= mtr_spawn($::exe_mysqladmin, $args,
@@ -632,7 +666,8 @@ sub mtr_mysqladmin_shutdown () {
$mysql_admin_pids{$pid}= 1;
}
- # We wait blocking, we wait for the last one anyway
+ # As mysqladmin is such a simple program, we trust it to terminate.
+ # I.e. we wait blocking, and wait wait for them all before we go on.
while (keys %mysql_admin_pids)
{
foreach my $pid (keys %mysql_admin_pids)
@@ -651,7 +686,8 @@ sub mtr_mysqladmin_shutdown () {
my $timeout= 20; # 20 seconds max
my $res= 1; # If we just fall through, we are done
-
+ # in the sense that the servers don't
+ # listen to their ports any longer
TIME:
while ( $timeout-- )
{
@@ -669,6 +705,8 @@ sub mtr_mysqladmin_shutdown () {
last; # If we got here, we are done
}
+ $timeout or mtr_debug("At least one server is still listening to its port");
+
sleep(5) if $::glob_win32; # FIXME next startup fails if no sleep
return $res;
@@ -752,6 +790,7 @@ sub mtr_ping_mysqld_server () {
#
##############################################################################
+# FIXME check that the pidfile contains the expected pid!
sub sleep_until_file_created ($$$) {
my $pidfile= shift;
@@ -762,7 +801,7 @@ sub sleep_until_file_created ($$$) {
{
if ( -r $pidfile )
{
- return 1;
+ return $pid;
}
# Check if it died after the fork() was successful
@@ -793,10 +832,18 @@ sub sleep_until_file_created ($$$) {
#
##############################################################################
+# FIXME something is wrong, we sometimes terminate with "Hangup" written
+# to tty, and no STDERR output telling us why.
+
+# FIXME for some readon, setting HUP to 'IGNORE' will cause exit() to
+# write out "Hangup", and maybe loose some output. We insert a sleep...
+
sub mtr_exit ($) {
my $code= shift;
+# cluck("Called mtr_exit()");
local $SIG{HUP} = 'IGNORE';
kill('HUP', -$$);
+ sleep 2;
exit($code);
}
diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl
index 0af34d11a3f..5e1a8308505 100644
--- a/mysql-test/lib/mtr_report.pl
+++ b/mysql-test/lib/mtr_report.pl
@@ -10,7 +10,6 @@ sub mtr_report_test_name($);
sub mtr_report_test_passed($);
sub mtr_report_test_failed($);
sub mtr_report_test_skipped($);
-sub mtr_report_test_disabled($);
sub mtr_show_failed_diff ($);
sub mtr_report_stats ($);
@@ -110,7 +109,14 @@ sub mtr_report_test_failed ($) {
my $tinfo= shift;
$tinfo->{'result'}= 'MTR_RES_FAILED';
- print "[ fail ]\n";
+ if ( $tinfo->{'timeout'} )
+ {
+ print "[ fail ] timeout\n";
+ }
+ else
+ {
+ print "[ fail ]\n";
+ }
# FIXME Instead of this test, and meaningless error message in 'else'
# we should write out into $::path_timefile when the error occurs.
diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl
new file mode 100644
index 00000000000..aab57d1bc52
--- /dev/null
+++ b/mysql-test/lib/mtr_timer.pl
@@ -0,0 +1,127 @@
+# -*- cperl -*-
+
+# This is a library file used by the Perl version of mysql-test-run,
+# and is part of the translation of the Bourne shell script with the
+# same name.
+
+use Carp qw(cluck);
+use Socket;
+use Errno;
+use strict;
+
+#use POSIX ":sys_wait_h";
+use POSIX 'WNOHANG';
+
+sub mtr_init_timers ();
+sub mtr_timer_start($$$);
+sub mtr_timer_stop($$);
+sub mtr_timer_waitpid($$$);
+
+##############################################################################
+#
+# Initiate a structure shared by all timers
+#
+##############################################################################
+
+sub mtr_init_timers () {
+ my $timers = { timers => {}, pids => {}};
+ return $timers;
+}
+
+
+##############################################################################
+#
+# Start, stop and poll a timer
+#
+# As alarm() isn't portable to Windows, we use separate processes to
+# implement timers. That is why there is a mtr_timer_waitpid(), as this
+# is where we catch a timeout.
+#
+##############################################################################
+
+sub mtr_timer_start($$$) {
+ my ($timers,$name,$duration)= @_;
+
+ if ( exists $timers->{'timers'}->{$name} )
+ {
+ # We have an old running timer, kill it
+ mtr_timer_stop($timers,$name);
+ }
+
+ FORK:
+ {
+ my $tpid= fork();
+
+ if ( ! defined $tpid )
+ {
+ if ( $! == $!{EAGAIN} ) # See "perldoc Errno"
+ {
+ mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo");
+ sleep(1);
+ redo FORK;
+ }
+ else
+ {
+ mtr_error("can't fork");
+ }
+ }
+
+ if ( $tpid )
+ {
+ # Parent, record the information
+ $timers->{'timers'}->{$name}->{'pid'}= $tpid;
+ $timers->{'timers'}->{$name}->{'duration'}= $duration;
+ $timers->{'pids'}->{$tpid}= $name;
+ }
+ else
+ {
+ # Child, redirect output and exec
+ # FIXME do we need to redirect streams?
+ $0= "mtr_timer(timers,$name,$duration)";
+ sleep($duration);
+ exit(0);
+ }
+ }
+}
+
+
+sub mtr_timer_stop ($$) {
+ my ($timers,$name)= @_;
+
+ if ( exists $timers->{'timers'}->{$name} )
+ {
+ my $tpid= $timers->{'timers'}->{$name}->{'pid'};
+
+ # FIXME as Cygwin reuses pids fast, maybe check that is
+ # the expected process somehow?!
+ kill(9, $tpid);
+
+ # As the timers are so simple programs, we trust them to terminate,
+ # and use blocking wait for it. We wait just to avoid a zombie.
+ waitpid($tpid,0);
+
+ delete $timers->{'timers'}->{$name}; # Remove the timer information
+ delete $timers->{'pids'}->{$tpid}; # and PID reference
+
+ return 1;
+ }
+ else
+ {
+ mtr_debug("Asked to stop timer \"$name\" not started");
+ return 0;
+ }
+}
+
+
+sub mtr_timer_timeout ($$) {
+ my ($timers,$pid)= @_;
+
+ return "" unless exists $timers->{'pids'}->{$pid};
+
+ # We got a timeout
+ my $name= $timers->{'pids'}->{$pid};
+ mtr_timer_stop($timers, $timers->{'timers'}->{$name});
+ return $name;
+}
+
+1;
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index b70379d8597..8dbe90fac54 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -90,6 +90,7 @@ use strict;
require "lib/mtr_cases.pl";
require "lib/mtr_process.pl";
+require "lib/mtr_timer.pl";
require "lib/mtr_io.pl";
require "lib/mtr_gcov.pl";
require "lib/mtr_gprof.pl";
@@ -137,6 +138,7 @@ our $glob_mysql_test_dir= undef;
our $glob_mysql_bench_dir= undef;
our $glob_hostname= undef;
our $glob_scriptname= undef;
+our $glob_timers= undef;
our $glob_use_running_server= 0;
our $glob_use_running_ndbcluster= 0;
our $glob_use_embedded_server= 0;
@@ -232,8 +234,10 @@ our $opt_skip_test;
our $opt_sleep;
our $opt_ps_protocol;
-our $opt_sleep_time_after_restart= 1;
+our $opt_sleep_time_after_restart= 1;
our $opt_sleep_time_for_delete= 10;
+our $opt_testcase_timeout= 5; # 5 min max
+our $opt_suite_timeout= 120; # 2 hours max
our $opt_socket;
@@ -341,7 +345,6 @@ sub main () {
if ( ! $glob_use_running_server )
{
-
if ( $opt_start_dirty )
{
kill_running_server();
@@ -356,7 +359,7 @@ sub main () {
}
}
- if ( $opt_start_and_exit or $opt_start_dirty )
+ if ( $opt_start_dirty )
{
if ( ndbcluster_start() )
{
@@ -371,16 +374,13 @@ sub main () {
mtr_error("Can't start the mysqld server");
}
}
+ elsif ( $opt_bench )
+ {
+ run_benchmarks(shift); # Shift what? Extra arguments?!
+ }
else
{
- if ( $opt_bench )
- {
- run_benchmarks(shift); # Shift what? Extra arguments?!
- }
- else
- {
- run_tests();
- }
+ run_tests();
}
mtr_exit(0);
@@ -418,7 +418,7 @@ sub initial_setup () {
$opt_source_dist= 1;
}
- $glob_hostname= mtr_full_hostname();
+ $glob_hostname= mtr_short_hostname();
# 'basedir' is always parent of "mysql-test" directory
$glob_mysql_test_dir= cwd();
@@ -439,6 +439,8 @@ sub initial_setup () {
$path_my_basedir=
$opt_source_dist ? $glob_mysql_test_dir : $glob_basedir;
+
+ $glob_timers= mtr_init_timers();
}
@@ -534,6 +536,8 @@ sub command_line_setup () {
'vardir=s' => \$opt_vardir,
'verbose' => \$opt_verbose,
'wait-timeout=i' => \$opt_wait_timeout,
+ 'testcase-timeout=i' => \$opt_testcase_timeout,
+ 'suite-timeout=i' => \$opt_suite_timeout,
'warnings|log-warnings' => \$opt_warnings,
'with-openssl' => \$opt_with_openssl,
@@ -1198,6 +1202,8 @@ sub run_suite () {
mtr_report("Finding Tests in the '$suite' suite");
+ mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout);
+
my $tests= collect_test_cases($suite);
mtr_report("Starting Tests in the '$suite' suite");
@@ -1206,7 +1212,9 @@ sub run_suite () {
foreach my $tinfo ( @$tests )
{
+ mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout);
run_testcase($tinfo);
+ mtr_timer_stop($glob_timers,"testcase");
}
mtr_print_line();
@@ -1227,6 +1235,8 @@ sub run_suite () {
}
mtr_report_stats($tests);
+
+ mtr_timer_stop($glob_timers,"suite");
}
@@ -1488,6 +1498,16 @@ sub run_testcase ($) {
}
# ----------------------------------------------------------------------
+ # If --start-and-exit given, stop here to let user manually run tests
+ # ----------------------------------------------------------------------
+
+ if ( $opt_start_and_exit )
+ {
+ mtr_report("\nServers started, exiting");
+ exit(0);
+ }
+
+ # ----------------------------------------------------------------------
# Run the test case
# ----------------------------------------------------------------------
@@ -1514,6 +1534,11 @@ sub run_testcase ($) {
# Testcase itself tell us to skip this one
mtr_report_test_skipped($tinfo);
}
+ elsif ( $res == 63 )
+ {
+ $tinfo->{'timeout'}= 1; # Mark as timeout
+ report_failure_and_restart($tinfo);
+ }
else
{
# Test case failed, if in control mysqltest returns 1
@@ -1649,8 +1674,6 @@ sub mysqld_arguments ($$$$$) {
my $extra_opt= shift;
my $slave_master_info= shift;
-# print STDERR Dumper($extra_opt);
-
my $sidx= ""; # Index as string, 0 is empty string
if ( $idx > 0 )
{
@@ -2020,6 +2043,7 @@ sub run_mysqltest ($) {
my $tinfo= shift;
my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
+ "--port=$master->[0]->{'path_myport'} " .
"--socket=$master->[0]->{'path_mysock'} --password=";
if ( $opt_debug )
{
@@ -2028,6 +2052,7 @@ sub run_mysqltest ($) {
}
my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " .
+ "--port=$master->[0]->{'path_myport'} " .
"--socket=$master->[0]->{'path_mysock'} --password=";
if ( $opt_debug )
{
@@ -2248,13 +2273,18 @@ Misc options
script-debug Debug this script itself
compress Use the compressed protocol between client and server
timer Show test case execution time
- start-and-exit Only initiate and start the "mysqld" servers
+ start-and-exit Only initiate and start the "mysqld" servers, use the startup
+ settings for the specified test case if any
start-dirty Only start the "mysqld" servers without initiation
fast Don't try to cleanup from earlier runs
reorder Reorder tests to get less server restarts
help Get this help text
unified-diff | udiff When presenting differences, use unified diff
+ testcase-timeout=MINUTES Max test case run time (default 5)
+ suite-timeout=MINUTES Max test suite run time (default 120)
+
+
Options not yet described, or that I want to look into more
big-test
@@ -2274,4 +2304,5 @@ Options not yet described, or that I want to look into more
HERE
mtr_exit(1);
+
}
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 6e2d062188d..5bb464665a0 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -314,7 +314,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty');
SHOW INDEX FROM t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE
-t1 0 PRIMARY 2 User A 3 NULL NULL BTREE
+t1 0 PRIMARY 2 User A 0 NULL NULL BTREE
ALTER TABLE t1 ENABLE KEYS;
UNLOCK TABLES;
CHECK TABLES t1;
@@ -338,7 +338,7 @@ INSERT INTO t1 VALUES ('localhost','root'),('localhost','');
SHOW INDEX FROM t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE
-t1 0 PRIMARY 2 User A 2 NULL NULL BTREE
+t1 0 PRIMARY 2 User A 0 NULL NULL BTREE
t1 1 Host 1 Host A NULL NULL NULL BTREE disabled
ALTER TABLE t1 ENABLE KEYS;
SHOW INDEX FROM t1;
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index 876da3cb964..d525b019c64 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -737,6 +737,11 @@ a
1
2
3
+select a from t1 natural join t1 as t2 where b >= @a order by a;
+a
+1
+2
+3
update t1 set a=5 where a=1;
select a from t1;
a
diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result
index a0c8f317db2..1b5619eb18d 100644
--- a/mysql-test/r/bigint.result
+++ b/mysql-test/r/bigint.result
@@ -17,6 +17,15 @@ select 9223372036854775808+1;
select -(0-3),round(-(0-3)), round(9999999999999999999);
-(0-3) round(-(0-3)) round(9999999999999999999)
3 3 9999999999999999999
+select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
+1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
+1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
+select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001;
+-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001
+-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001
+select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
+conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16)
+1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5
create table t1 (a bigint unsigned not null, primary key(a));
insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612);
select * from t1;
diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result
index 2661ff5e3c9..08206a91b7b 100755
--- a/mysql-test/r/ctype_cp932.result
+++ b/mysql-test/r/ctype_cp932.result
@@ -11315,6 +11315,20 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
+RESET MASTER;
+CREATE TABLE t1(f1 blob);
+PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)';
+SET @var1= x'8300';
+EXECUTE stmt1 USING @var1;
+SHOW BINLOG EVENTS FROM 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 185 use `test`; CREATE TABLE t1(f1 blob)
+master-bin.000001 185 User var 1 224 @`var1`=_binary 0x8300 COLLATE binary
+master-bin.000001 224 Query 1 317 use `test`; INSERT INTO t1 VALUES(@'var1')
+SELECT HEX(f1) FROM t1;
+HEX(f1)
+8300
+DROP table t1;
SET collation_connection='cp932_japanese_ci';
create table t1 select repeat('a',4000) a;
delete from t1;
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result
index fd6a834c694..7c9d88acf90 100644
--- a/mysql-test/r/derived.result
+++ b/mysql-test/r/derived.result
@@ -111,7 +111,7 @@ a b
1 a
2 b
3 c
-explain select * from (select * from t1,t2 where t1.a=t2.a) t1;
+explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
2 DERIVED t2 system NULL NULL NULL NULL 1
@@ -149,8 +149,8 @@ SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b;
(SELECT * FROM (SELECT 1 as a) as a )
1
select * from (select 1 as a) b left join (select 2 as a) c using(a);
-a a
-1 NULL
+a
+1
SELECT * FROM (SELECT 1 UNION SELECT a) b;
ERROR 42S22: Unknown column 'a' in 'field list'
SELECT 1 as a FROM (SELECT a UNION SELECT 1) b;
@@ -363,3 +363,8 @@ a
3
3
drop table t1, t2, t3;
+create table t1 (a int);
+create table t2 (a int);
+select * from (select * from t1,t2) foo;
+ERROR 42S21: Duplicate column name 'a'
+drop table t1,t2;
diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result
index 3ad2b73f1d3..fa52b5c8330 100644
--- a/mysql-test/r/distinct.result
+++ b/mysql-test/r/distinct.result
@@ -472,3 +472,51 @@ id IFNULL(dsc, '-')
2 line number two
3 line number three
drop table t1;
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+SELECT DISTINCT a, 1 FROM t1;
+a 1
+1 1
+2 1
+3 1
+4 1
+5 1
+SELECT DISTINCT 1, a FROM t1;
+1 a
+1 1
+1 2
+1 3
+1 4
+1 5
+CREATE TABLE t2 (a int, b int);
+INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5);
+SELECT DISTINCT a, b, 2 FROM t2;
+a b 2
+1 1 2
+2 2 2
+2 3 2
+2 4 2
+3 5 2
+SELECT DISTINCT 2, a, b FROM t2;
+2 a b
+2 1 1
+2 2 2
+2 2 3
+2 2 4
+2 3 5
+SELECT DISTINCT a, 2, b FROM t2;
+a 2 b
+1 2 1
+2 2 2
+2 2 3
+2 2 4
+3 2 5
+DROP TABLE t1,t2;
+create table t1 (id int, dsc varchar(50));
+insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three");
+select distinct id, IFNULL(dsc, '-') from t1;
+id IFNULL(dsc, '-')
+1 line number one
+2 line number two
+3 line number three
+drop table t1;
diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result
index d0011c8deb6..0c84f24a2e4 100644
--- a/mysql-test/r/errors.result
+++ b/mysql-test/r/errors.result
@@ -9,9 +9,9 @@ create table t1 (a int);
select count(test.t1.b) from t1;
ERROR 42S22: Unknown column 'test.t1.b' in 'field list'
select count(not_existing_database.t1) from t1;
-ERROR 42S02: Unknown table 'not_existing_database' in field list
+ERROR 42S22: Unknown column 'not_existing_database.t1' in 'field list'
select count(not_existing_database.t1.a) from t1;
-ERROR 42S02: Unknown table 'not_existing_database.t1' in field list
+ERROR 42S22: Unknown column 'not_existing_database.t1.a' in 'field list'
select count(not_existing_database.t1.a) from not_existing_database.t1;
Got one of the listed errors
select 1 from t1 order by 2;
@@ -23,3 +23,8 @@ ERROR 42S22: Unknown column 't1.b' in 'order clause'
select count(*),b from t1;
ERROR 42S22: Unknown column 'b' in 'field list'
drop table t1;
+create table t1 (a int(256));
+ERROR 42000: Display width out of range for column 'a' (max = 255)
+set sql_mode='traditional';
+create table t1 (a varchar(66000));
+ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead
diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result
index 306376b13c3..16c308e3450 100644
--- a/mysql-test/r/flush.result
+++ b/mysql-test/r/flush.result
@@ -27,3 +27,24 @@ select * from t1;
n
345
drop table t1;
+create table t1 (c1 int);
+lock table t1 write;
+flush tables with read lock;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+lock table t1 read;
+flush tables with read lock;
+lock table t1 write;
+ERROR HY000: Can't execute the query because you have a conflicting read lock
+lock table t1 read;
+lock table t1 write;
+ERROR HY000: Can't execute the query because you have a conflicting read lock
+unlock tables;
+create table t2 (c1 int);
+create table t3 (c1 int);
+lock table t1 read, t2 read, t3 write;
+flush tables with read lock;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+lock table t1 read, t2 read, t3 read;
+flush tables with read lock;
+unlock tables;
+drop table t1, t2, t3;
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index 6a41035eb7b..ea0ffe9d7dd 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -221,14 +221,14 @@ select t1.id FROM t2 as ttxt,t1,t1 as ticket2
WHERE ticket2.id = ttxt.ticket AND t1.id = ticket2.ticket and
match(ttxt.inhalt) against ('foobar');
id
-select t1.id FROM t2 as ttxt,t1 INNER JOIN t1 as ticket2 ON
-ticket2.id = ttxt.ticket
-WHERE t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar');
+select ticket2.id FROM t2 as ttxt,t2 INNER JOIN t1 as ticket2 ON
+ticket2.id = t2.ticket
+WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar');
id
INSERT INTO t1 VALUES (3,3);
-select t1.id FROM t2 as ttxt,t1
-INNER JOIN t1 as ticket2 ON ticket2.id = ttxt.ticket
-WHERE t1.id = ticket2.ticket and
+select ticket2.id FROM t2 as ttxt,t2
+INNER JOIN t1 as ticket2 ON ticket2.id = t2.ticket
+WHERE ticket2.id = ticket2.ticket and
match(ttxt.inhalt) against ('foobar');
id
3
@@ -337,8 +337,8 @@ insert into t2 values (1, 1, 'xxfoo');
insert into t2 values (2, 1, 'xxbar');
insert into t2 values (3, 1, 'xxbuz');
select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode);
-t1_id name t2_id t1_id name
-1 data1 1 1 xxfoo
+t1_id name t2_id name
+1 data1 1 xxfoo
select * from t2 where match name against ('*a*b*c*d*e*f*' in boolean mode);
t2_id t1_id name
drop table t1,t2;
diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result
index 3b52be4b1f2..bc466b5aba7 100644
--- a/mysql-test/r/fulltext_order_by.result
+++ b/mysql-test/r/fulltext_order_by.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1,t2,t3;
CREATE TABLE t1 (
a INT AUTO_INCREMENT PRIMARY KEY,
message CHAR(20),
@@ -126,7 +126,7 @@ group by
a.text, b.id, b.betreff
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
-ERROR 42S02: Unknown table 'b' in order clause
+ERROR 42S22: Unknown column 'b.betreff' in 'order clause'
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@@ -142,7 +142,7 @@ where
match(c.beitrag) against ('+abc' in boolean mode)
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
-ERROR 42S02: Unknown table 'b' in order clause
+ERROR 42S22: Unknown column 'b.betreff' in 'order clause'
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@@ -158,5 +158,19 @@ where
match(c.beitrag) against ('+abc' in boolean mode)
order by
match(betreff) against ('+abc' in boolean mode) desc;
-ERROR HY000: The used table type doesn't support FULLTEXT indexes
+text id betreff
+(select b.id, b.betreff from t3 b) union
+(select b.id, b.betreff from t3 b)
+order by match(betreff) against ('+abc' in boolean mode) desc;
+id betreff
+(select b.id, b.betreff from t3 b) union
+(select b.id, b.betreff from t3 b)
+order by match(betreff) against ('+abc') desc;
+ERROR HY000: Can't find FULLTEXT index matching the column list
+select distinct b.id, b.betreff from t3 b
+order by match(betreff) against ('+abc' in boolean mode) desc;
+id betreff
+select b.id, b.betreff from t3 b group by b.id+1
+order by match(betreff) against ('+abc' in boolean mode) desc;
+id betreff
drop table t1,t2,t3;
diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result
index 50889943b56..841d13a6ea6 100644
--- a/mysql-test/r/func_date_add.result
+++ b/mysql-test/r/func_date_add.result
@@ -45,3 +45,29 @@ visitor_id mts
465931136 2000-03-18 16:09:53
1092858576 2000-03-19 01:34:45
drop table t1;
+set sql_mode='traditional';
+create table t1 (d date);
+insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR);
+ERROR 22008: Datetime function: datetime field overflow
+insert into t1 (d) select date_add('2000-01-01',interval 8000 year);
+ERROR 22008: Datetime function: datetime field overflow
+insert into t1 values (date_add(NULL, INTERVAL 1 DAY));
+insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY));
+set sql_mode='';
+insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR);
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
+insert into t1 (d) select date_add('2000-01-01',interval 8000 year);
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
+insert into t1 values (date_add(NULL, INTERVAL 1 DAY));
+insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY));
+select * from t1;
+d
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+drop table t1;
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 5e74e6fa68a..36666fc827d 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -59,3 +59,38 @@ t1 CREATE TABLE `t1` (
`length(uuid())` int(10) NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
+create table t1 (a timestamp default '2005-05-05 01:01:01',
+b timestamp default '2005-05-05 01:01:01');
+insert into t1 set a = now();
+select sleep(3);
+sleep(3)
+0
+update t1 set b = now();
+select timediff(b, a) >= '00:00:03' from t1;
+timediff(b, a) >= '00:00:03'
+1
+drop table t1;
+set global query_cache_size=1355776;
+create table t1 (a int);
+insert into t1 values (1),(1),(1);
+create table t2 (a datetime default null, b datetime default null);
+insert into t2 set a = now();
+select a from t1 where sleep(1);
+a
+update t2 set b = now() where b is null;
+insert into t2 set a = now();
+select a from t1 where sleep(a);
+a
+update t2 set b = now() where b is null;
+insert into t2 set a = now();
+select a from t1 where sleep(1);
+a
+update t2 set b = now() where b is null;
+select timediff(b, a) >= '00:00:03' from t2;
+timediff(b, a) >= '00:00:03'
+1
+1
+1
+drop table t2;
+drop table t1;
+set global query_cache_size=default;
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 57942d1fcdf..c7e69ae1d31 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -45,6 +45,123 @@ www. .se
select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1);
substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1)
tcx.se .se
+select substring_index('aaaaaaaaa1','a',1);
+substring_index('aaaaaaaaa1','a',1)
+
+select substring_index('aaaaaaaaa1','aa',1);
+substring_index('aaaaaaaaa1','aa',1)
+
+select substring_index('aaaaaaaaa1','aa',2);
+substring_index('aaaaaaaaa1','aa',2)
+aa
+select substring_index('aaaaaaaaa1','aa',3);
+substring_index('aaaaaaaaa1','aa',3)
+aaaa
+select substring_index('aaaaaaaaa1','aa',4);
+substring_index('aaaaaaaaa1','aa',4)
+aaaaaa
+select substring_index('aaaaaaaaa1','aa',5);
+substring_index('aaaaaaaaa1','aa',5)
+aaaaaaaaa1
+select substring_index('aaaaaaaaa1','aaa',1);
+substring_index('aaaaaaaaa1','aaa',1)
+
+select substring_index('aaaaaaaaa1','aaa',2);
+substring_index('aaaaaaaaa1','aaa',2)
+aaa
+select substring_index('aaaaaaaaa1','aaa',3);
+substring_index('aaaaaaaaa1','aaa',3)
+aaaaaa
+select substring_index('aaaaaaaaa1','aaa',4);
+substring_index('aaaaaaaaa1','aaa',4)
+aaaaaaaaa1
+select substring_index('aaaaaaaaa1','aaaa',1);
+substring_index('aaaaaaaaa1','aaaa',1)
+
+select substring_index('aaaaaaaaa1','aaaa',2);
+substring_index('aaaaaaaaa1','aaaa',2)
+aaaa
+select substring_index('aaaaaaaaa1','1',1);
+substring_index('aaaaaaaaa1','1',1)
+aaaaaaaaa
+select substring_index('aaaaaaaaa1','a',-1);
+substring_index('aaaaaaaaa1','a',-1)
+1
+select substring_index('aaaaaaaaa1','aa',-1);
+substring_index('aaaaaaaaa1','aa',-1)
+1
+select substring_index('aaaaaaaaa1','aa',-2);
+substring_index('aaaaaaaaa1','aa',-2)
+aa1
+select substring_index('aaaaaaaaa1','aa',-3);
+substring_index('aaaaaaaaa1','aa',-3)
+aaaa1
+select substring_index('aaaaaaaaa1','aa',-4);
+substring_index('aaaaaaaaa1','aa',-4)
+aaaaaa1
+select substring_index('aaaaaaaaa1','aa',-5);
+substring_index('aaaaaaaaa1','aa',-5)
+aaaaaaaaa1
+select substring_index('aaaaaaaaa1','aaa',-1);
+substring_index('aaaaaaaaa1','aaa',-1)
+1
+select substring_index('aaaaaaaaa1','aaa',-2);
+substring_index('aaaaaaaaa1','aaa',-2)
+aaa1
+select substring_index('aaaaaaaaa1','aaa',-3);
+substring_index('aaaaaaaaa1','aaa',-3)
+aaaaaa1
+select substring_index('aaaaaaaaa1','aaa',-4);
+substring_index('aaaaaaaaa1','aaa',-4)
+
+select substring_index('the king of thethe hill','the',-2);
+substring_index('the king of thethe hill','the',-2)
+the hill
+select substring_index('the king of the the hill','the',-2);
+substring_index('the king of the the hill','the',-2)
+ the hill
+select substring_index('the king of the the hill','the',-2);
+substring_index('the king of the the hill','the',-2)
+ the hill
+select substring_index('the king of the the hill',' the ',-1);
+substring_index('the king of the the hill',' the ',-1)
+hill
+select substring_index('the king of the the hill',' the ',-2);
+substring_index('the king of the the hill',' the ',-2)
+ the hill
+select substring_index('the king of the the hill',' ',-1);
+substring_index('the king of the the hill',' ',-1)
+hill
+select substring_index('the king of the the hill',' ',-2);
+substring_index('the king of the the hill',' ',-2)
+the hill
+select substring_index('the king of the the hill',' ',-3);
+substring_index('the king of the the hill',' ',-3)
+ the hill
+select substring_index('the king of the the hill',' ',-4);
+substring_index('the king of the the hill',' ',-4)
+the the hill
+select substring_index('the king of the the hill',' ',-5);
+substring_index('the king of the the hill',' ',-5)
+of the the hill
+select substring_index('the king of the.the hill','the',-2);
+substring_index('the king of the.the hill','the',-2)
+.the hill
+select substring_index('the king of thethethe.the hill','the',-3);
+substring_index('the king of thethethe.the hill','the',-3)
+the.the hill
+select substring_index('the king of thethethe.the hill','the',-1);
+substring_index('the king of thethethe.the hill','the',-1)
+ hill
+select substring_index('the king of the the hill','the',1);
+substring_index('the king of the the hill','the',1)
+
+select substring_index('the king of the the hill','the',2);
+substring_index('the king of the the hill','the',2)
+the king of
+select substring_index('the king of the the hill','the',3);
+substring_index('the king of the the hill','the',3)
+the king of the
select concat(':',ltrim(' left '),':',rtrim(' right '),':');
concat(':',ltrim(' left '),':',rtrim(' right '),':')
:left : right:
diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result
index 5ec5d7d724e..1c1c6dff21e 100644
--- a/mysql-test/r/func_system.result
+++ b/mysql-test/r/func_system.result
@@ -68,6 +68,21 @@ drop table t1;
select TRUE,FALSE,NULL;
TRUE FALSE NULL
1 0 NULL
+create table t1 (c1 char(5)) character set=latin1;
+insert into t1 values('row 1');
+insert into t1 values('row 2');
+insert into t1 values('row 3');
+select concat(user(), '--', c1) from t1;
+concat(user(), '--', c1)
+root@localhost--row 1
+root@localhost--row 2
+root@localhost--row 3
+select concat(database(), '--', c1) from t1;
+concat(database(), '--', c1)
+test--row 1
+test--row 2
+test--row 3
+drop table t1;
create table t1 (a char(10)) character set latin1;
select * from t1 where a=version();
a
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 63da5589c57..87aa4b98d81 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -247,9 +247,13 @@ date_add("1997-12-31 23:59:59",INTERVAL -100000 DAY)
select date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH);
date_add("1997-12-31 23:59:59",INTERVAL 100000 MONTH)
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
select date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR);
date_add("1997-12-31 23:59:59",INTERVAL -100000 YEAR)
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
select date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND);
date_add("1997-12-31 23:59:59",INTERVAL "10000:1" MINUTE_SECOND)
1998-01-07 22:40:00
@@ -301,6 +305,8 @@ NULL
select date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND);
date_add("9999-12-31 23:59:59",INTERVAL 1 SECOND)
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
select date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND);
date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND)
NULL
@@ -375,15 +381,23 @@ SELECT "1900-01-01 00:00:00" + INTERVAL 1<<20 HOUR;
SELECT "1900-01-01 00:00:00" + INTERVAL 1<<38 SECOND;
"1900-01-01 00:00:00" + INTERVAL 1<<38 SECOND
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
SELECT "1900-01-01 00:00:00" + INTERVAL 1<<33 MINUTE;
"1900-01-01 00:00:00" + INTERVAL 1<<33 MINUTE
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
SELECT "1900-01-01 00:00:00" + INTERVAL 1<<30 HOUR;
"1900-01-01 00:00:00" + INTERVAL 1<<30 HOUR
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
SELECT "1900-01-01 00:00:00" + INTERVAL "1000000000:214748364700" MINUTE_SECOND;
"1900-01-01 00:00:00" + INTERVAL "1000000000:214748364700" MINUTE_SECOND
NULL
+Warnings:
+Warning 1441 Datetime function: datetime field overflow
create table t1 (ctime varchar(20));
insert into t1 values ('2001-01-12 12:23:40');
select ctime, hour(ctime) from t1;
@@ -687,7 +701,7 @@ timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select timestamp_diff(WEEK,_latin1'2001-02-01',_latin1'2001-05-01') AS `a1`,timestamp_diff(SECOND_FRAC,_latin1'2001-02-01 12:59:59.120000',_latin1'2001-05-01 12:58:58.119999') AS `a2`
+Note 1003 select timestampdiff(WEEK,_latin1'2001-02-01',_latin1'2001-05-01') AS `a1`,timestampdiff(SECOND_FRAC,_latin1'2001-02-01 12:59:59.120000',_latin1'2001-05-01 12:58:58.119999') AS `a2`
select last_day('2005-00-00');
last_day('2005-00-00')
NULL
@@ -706,3 +720,43 @@ Warning 1292 Truncated incorrect datetime value: '2005-01-00'
select time_format('100:00:00', '%H %k %h %I %l');
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');
+create function t_slow_sysdate() returns timestamp
+begin
+do sleep(2);
+return sysdate();
+end;
+//
+insert into t1 set a = sysdate(), b = t_slow_sysdate();//
+create trigger t_before before insert on t1
+for each row begin
+set new.b = t_slow_sysdate();
+end
+//
+insert into t1 set a = sysdate();
+select a != b from t1;
+a != b
+1
+1
+drop trigger t_before;
+drop function t_slow_sysdate;
+drop table t1;
+create table t1 (a datetime, i int, b datetime);
+insert into t1 select sysdate(), sleep(1), sysdate() from dual;
+select a != b from t1;
+a != b
+1
+drop table t1;
+create procedure t_sysdate()
+begin
+select sysdate() into @a;
+do sleep(2);
+select sysdate() into @b;
+select @a != @b;
+end;
+//
+call t_sysdate();
+@a != @b
+1
+drop procedure t_sysdate;
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index 19982c7bb60..14393be1cc8 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -591,3 +591,6 @@ 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;
+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
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index dd35d1c3dac..7ac10de1f7c 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -284,5 +284,31 @@ i
2
3
REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
drop table mysqltest_1.t1;
+grant all on mysqltest_1.* to mysqltest_1@'127.0.0.1';
+select current_user();
+current_user()
+mysqltest_1@127.0.0.1
+set password = password('changed');
+select host, length(password) from mysql.user where user like 'mysqltest\_1';
+host length(password)
+127.0.0.1 41
+revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.1';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
+grant all on mysqltest_1.* to mysqltest_1@'127.0.0.0/255.0.0.0';
+select current_user();
+current_user()
+mysqltest_1@127.0.0.0/255.0.0.0
+set password = password('changed');
+select host, length(password) from mysql.user where user like 'mysqltest\_1';
+host length(password)
+127.0.0.0/255.0.0.0 41
+revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.0/255.0.0.0';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
drop database mysqltest_1;
+set password = password("changed");
+ERROR 42000: Access denied for user ''@'localhost' to database 'mysql'
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index 64446e63e6f..f4cf5217fa7 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -751,6 +751,13 @@ COUNT(DISTINCT(t1.id)) comment
1 NULL
1 a problem
DROP TABLE t1, t2;
+create table t1 (f1 date);
+insert into t1 values('2005-06-06');
+insert into t1 values('2005-06-06');
+select date(left(f1+0,8)) from t1 group by 1;
+date(left(f1+0,8))
+2005-06-06
+drop table t1;
CREATE TABLE t1 (n int);
INSERT INTO t1 VALUES (1);
SELECT n+1 AS n FROM t1 GROUP BY n;
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index b905dae3aba..969cb06e9fe 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -701,3 +701,10 @@ insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd
insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 1
drop table t1;
+create table t1 (c char(10)) engine=memory;
+create table t2 (c varchar(10)) engine=memory;
+show table status like 't_';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 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;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 5688d8c2145..6d8907fff00 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t0,t1,t2;
+DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
show variables where variable_name like "skip_show_database";
Variable_name Value
skip_show_database OFF
@@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
create table test.t2(a int);
create table t3(a int, KEY a_data (a));
create table mysqltest.t4(a int);
+create table t5 (id int auto_increment primary key);
+insert into t5 values (10);
create view v1 (c) as select table_name from information_schema.TABLES;
select * from v1;
c
@@ -70,6 +72,7 @@ t1
t4
t2
t3
+t5
v1
select c,table_name from v1
inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
@@ -89,6 +92,7 @@ t1 t1
t4 t4
t2 t2
t3 t3
+t5 t5
select c,table_name from v1
left join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -107,6 +111,7 @@ t1 t1
t4 t4
t2 t2
t3 t3
+t5 t5
select c, v2.table_name from v1
right join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -125,6 +130,7 @@ t1 t1
t4 t4
t2 t2
t3 t3
+t5 t5
select table_name from information_schema.TABLES
where table_schema = "mysqltest" and table_name like "t%";
table_name
@@ -140,11 +146,13 @@ show tables like 't%';
Tables_in_test (t%)
t2
t3
+t5
show table status;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
t3 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
-v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
+t5 MyISAM 10 Fixed 1 7 7 # 2048 0 11 # # NULL latin1_swedish_ci NULL
+v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
show full columns from t3 like "a%";
Field Type Collation Null Key Default Extra Privileges Comment
a int(11) NULL YES MUL NULL select,insert,update,references
@@ -157,7 +165,7 @@ c varchar(64) utf8_general_ci NO select,insert,update,references
select * from information_schema.COLUMNS where table_name="t1"
and column_name= "a";
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT
-NULL mysqltest t1 a 1 NULL YES int NULL NULL 10 NULL NULL NULL int(11) select,insert,update,references
+NULL mysqltest t1 a 1 NULL YES int NULL NULL 10 0 NULL NULL int(11) select,insert,update,references
show columns from mysqltest.t1 where field like "%a%";
Field Type Null Key Default Extra
a int(11) YES NULL
@@ -177,7 +185,7 @@ where table_schema = 'mysqltest' and table_name = 'v1';
table_name column_name privileges
v1 c select
drop view v1, mysqltest.v1;
-drop tables mysqltest.t4, mysqltest.t1, t2, t3;
+drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5;
drop database mysqltest;
select * from information_schema.CHARACTER_SETS
where CHARACTER_SET_NAME like 'latin1%';
@@ -265,10 +273,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE # ALL NULL NULL NULL NULL 2
1 SIMPLE # ALL NULL NULL NULL NULL 2 Using where
select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
-mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
+mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8) order by 1;
ROUTINE_NAME name
-sub1 sub1
sel2 sel2
+sub1 sub1
select count(*) from information_schema.ROUTINES;
count(*)
2
@@ -527,7 +535,7 @@ c float(5,2) NULL NULL 5 2
d decimal(6,4) NULL NULL 6 4
e float NULL NULL 12 NULL
f decimal(6,3) NULL NULL 6 3
-g int(11) NULL NULL 10 NULL
+g int(11) NULL NULL 10 0
h double(10,3) NULL NULL 10 3
i double NULL NULL 22 NULL
drop table t1;
@@ -577,8 +585,8 @@ select TABLE_NAME,TABLE_TYPE,ENGINE
from information_schema.tables
where table_schema='information_schema' limit 2;
TABLE_NAME TABLE_TYPE ENGINE
-CHARACTER_SETS TEMPORARY MEMORY
-COLLATIONS TEMPORARY MEMORY
+CHARACTER_SETS SYSTEM VIEW MEMORY
+COLLATIONS SYSTEM VIEW MEMORY
show tables from information_schema like "T%";
Tables_in_information_schema (T%)
TABLES
@@ -590,10 +598,10 @@ ERROR HY000: Can't create database 'information_schema'; database exists
use information_schema;
show full tables like "T%";
Tables_in_information_schema (T%) Table_type
-TABLES TEMPORARY
-TABLE_CONSTRAINTS TEMPORARY
-TABLE_PRIVILEGES TEMPORARY
-TRIGGERS TEMPORARY
+TABLES SYSTEM VIEW
+TABLE_CONSTRAINTS SYSTEM VIEW
+TABLE_PRIVILEGES SYSTEM VIEW
+TRIGGERS SYSTEM VIEW
create table t1(a int);
ERROR 42S02: Unknown table 't1' in information_schema
use test;
@@ -933,11 +941,11 @@ select column_name, NUMERIC_PRECISION, NUMERIC_SCALE
from information_schema.columns
where table_name='t1';
column_name NUMERIC_PRECISION NUMERIC_SCALE
-f1 3 NULL
-f2 5 NULL
-f3 7 NULL
-f4 10 NULL
-f5 19 NULL
+f1 3 0
+f2 5 0
+f3 7 0
+f4 10 0
+f5 19 0
f6 1 NULL
f7 64 NULL
drop table t1;
@@ -950,3 +958,24 @@ trigger_schema trigger_name
test tr1
use test;
drop table t1;
+create table t1 (a int not null, b int);
+use information_schema;
+select column_name, column_default from columns
+where table_schema='test' and table_name='t1';
+column_name column_default
+a NULL
+b NULL
+use test;
+show columns from t1;
+Field Type Null Key Default Extra
+a int(11) NO
+b int(11) YES NULL
+drop table t1;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (b int);
+SHOW TABLE STATUS FROM test
+WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE');
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
+t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 2bdec5125dd..4b62e63c49b 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -755,6 +755,11 @@ a
1
2
3
+select a from t1 natural join t1 as t2 where b >= @a order by a;
+a
+1
+2
+3
update t1 set a=5 where a=1;
select a from t1;
a
@@ -904,7 +909,7 @@ insert into mysqltest.t3 values(1);
commit;
drop database mysqltest;
show tables from mysqltest;
-Got one of the listed errors
+ERROR 42000: Unknown database 'mysqltest'
set autocommit=0;
create table t1 (a int not null) engine= innodb;
insert into t1 values(1),(2);
@@ -1377,7 +1382,7 @@ ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fail
update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
-ERROR 42S02: Unknown table 't1' in where clause
+ERROR 42S22: Unknown column 't1.id' in 'where clause'
drop table t3,t2,t1;
create table t1(
id int primary key,
@@ -2475,3 +2480,11 @@ SELECT GRADE FROM t1 WHERE GRADE= 151;
GRADE
151
DROP TABLE t1;
+create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb;
+create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb;
+insert into t2 values ('aa','cc');
+insert into t1 values ('aa','bb'),('aa','cc');
+delete t1 from t1,t2 where f1=f3 and f4='cc';
+select * from t1;
+f1 f2
+drop table t1,t2;
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index f745af182eb..17f65d96abc 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -664,7 +664,7 @@ insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a +
insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
ERROR 23000: Column 'a' in field list is ambiguous
insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b;
-ERROR 42S02: Unknown table 't2' in field list
+ERROR 42S22: Unknown column 't2.a' in 'field list'
insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b;
-ERROR 42S02: Unknown table 't2' in field list
+ERROR 42S22: Unknown column 't2.b' in 'field list'
drop table t1,t2,t3;
diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result
index fc157093a7f..dbe5d600a95 100644
--- a/mysql-test/r/insert_update.result
+++ b/mysql-test/r/insert_update.result
@@ -191,3 +191,9 @@ ERROR 23000: Column 'a' in field list is ambiguous
insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ;
ERROR 23000: Column 't1.a' in field list is ambiguous
drop table t1;
+CREATE TABLE t1 (
+a BIGINT(20) NOT NULL DEFAULT 0,
+PRIMARY KEY (a)
+) ENGINE=MyISAM;
+INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ;
+DROP TABLE t1;
diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result
index dc763472b0e..c887dc9d6a7 100644
--- a/mysql-test/r/join.result
+++ b/mysql-test/r/join.result
@@ -10,21 +10,21 @@ SELECT * FROM t1 INNER JOIN t2;
S1 S1
1 2
SELECT * from t1 JOIN t2 USING (S1);
-S1 S1
+S1
SELECT * FROM t1 INNER JOIN t2 USING (S1);
-S1 S1
+S1
SELECT * from t1 CROSS JOIN t2;
S1 S1
1 2
SELECT * from t1 LEFT JOIN t2 USING(S1);
-S1 S1
-1 NULL
+S1
+1
SELECT * from t1 LEFT JOIN t2 ON(t2.S1=2);
S1 S1
1 2
SELECT * from t1 RIGHT JOIN t2 USING(S1);
-S1 S1
-NULL 2
+S1
+2
SELECT * from t1 RIGHT JOIN t2 ON(t1.S1=1);
S1 S1
1 2
@@ -127,6 +127,12 @@ a
2
select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
ERROR HY000: Too many tables; MySQL can only use XX tables in a join
+select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a);
+a
+1
+2
+select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
+ERROR HY000: Too many tables; MySQL can only use XX tables in a join
drop table t1;
CREATE TABLE t1 (
a int(11) NOT NULL,
@@ -146,9 +152,12 @@ CREATE TABLE t1 (d DATE NOT NULL);
CREATE TABLE t2 (d DATE NOT NULL);
INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00');
SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL;
-d d
-2001-08-01 NULL
-0000-00-00 NULL
+d
+2001-08-01
+0000-00-00
+SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL;
+d
+0000-00-00
SELECT * from t1 WHERE t1.d IS NULL;
d
0000-00-00
@@ -271,6 +280,12 @@ cust 20
SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith';
rate_code base_rate
cust 20
+SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats';
+rate_code base_rate
+cust 20
+SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith';
+rate_code base_rate
+cust 20
drop table t1,t2;
CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255));
CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255));
@@ -296,43 +311,43 @@ insert into t1 values(1),(2);
insert into t2 values(2),(3);
insert into t3 values (2),(4);
select * from t1 natural left join t2;
-i i
-1 NULL
-2 2
+i
+1
+2
select * from t1 left join t2 on (t1.i=t2.i);
i i
1 NULL
2 2
select * from t1 natural left join t2 natural left join t3;
-i i i
-1 NULL NULL
-2 2 2
+i
+1
+2
select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i);
i i i
1 NULL NULL
2 2 2
select * from t3 natural right join t2;
-i i
-2 2
-NULL 3
+i
+2
+3
select * from t3 right join t2 on (t3.i=t2.i);
i i
2 2
NULL 3
select * from t3 natural right join t2 natural right join t1;
-i i i
-NULL NULL 1
-2 2 2
+i
+1
+2
select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i);
i i i
NULL NULL 1
2 2 2
select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i;
-i i i
-1 2 2
-1 3 NULL
-2 2 2
-2 3 NULL
+i i
+1 2
+1 3
+2 2
+2 3
select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i;
i i i
1 2 2
@@ -352,11 +367,11 @@ i i i
2 2 2
2 3 NULL
select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i;
-i i i
-1 NULL 4
-1 2 2
-2 NULL 4
-2 2 2
+i i
+1 4
+1 2
+2 4
+2 2
select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i;
i i i
1 NULL 4
diff --git a/mysql-test/r/join_crash.result b/mysql-test/r/join_crash.result
index c1671ea7e20..f1a3b4956a8 100644
--- a/mysql-test/r/join_crash.result
+++ b/mysql-test/r/join_crash.result
@@ -75,18 +75,11 @@ t1.client_ptr as client_ptr,
t1.comments as comments,
sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget
from
-t1 ,
t2 as client_period ,
-t2 as project_period
-left join
-t3
-on
-t3.project_ptr = t1.project_id
-and t3.date_received <= '2001-03-22 14:15:09'
- left join
-t4
-on
-t4.client_id = t1.client_ptr
+t2 as project_period,
+t3 left join t1 on (t3.project_ptr = t1.project_id and
+t3.date_received <= '2001-03-22 14:15:09')
+left join t4 on t4.client_id = t1.client_ptr
where
1
and ( client_period.period_type = 'client_table'
diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result
index 27edac1b30b..f9a25898a6f 100644
--- a/mysql-test/r/join_nested.result
+++ b/mysql-test/r/join_nested.result
@@ -223,8 +223,7 @@ a b
1 2
EXPLAIN EXTENDED
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
-FROM t6,
-t7
+FROM (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10;
@@ -235,8 +234,7 @@ id select_type table type possible_keys key key_len ref rows Extra
Warnings:
Note 1003 select `test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t7`.`b` = `test`.`t8`.`b`) and (`test`.`t6`.`b` < 10))) where 1
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
-FROM t6,
-t7
+FROM (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10;
@@ -260,8 +258,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
FROM t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -279,8 +276,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
FROM t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -312,8 +308,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -357,8 +352,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -397,8 +391,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -470,8 +463,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -537,8 +529,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -575,8 +566,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -625,8 +615,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -679,8 +668,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -825,44 +813,38 @@ a b a b a b a b
1 3 5 3 NULL NULL NULL NULL
2 2 5 3 NULL NULL NULL NULL
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
-FROM t1, t3, t4
+FROM t1, (t3, t4)
RIGHT JOIN
t2
ON t3.a=1 AND t2.b=t4.b
WHERE t1.a <= 2;
a b a b a b a b
-1 3 3 3 1 2 NULL NULL
-1 3 3 3 2 2 NULL NULL
-2 2 3 3 1 2 NULL NULL
-2 2 3 3 2 2 NULL NULL
+1 3 3 3 NULL NULL NULL NULL
+2 2 3 3 NULL NULL NULL NULL
1 3 4 2 1 2 3 2
1 3 4 2 1 2 4 2
-1 3 4 2 2 2 NULL NULL
2 2 4 2 1 2 3 2
2 2 4 2 1 2 4 2
-2 2 4 2 2 2 NULL NULL
-1 3 5 3 1 2 NULL NULL
-1 3 5 3 2 2 NULL NULL
-2 2 5 3 1 2 NULL NULL
-2 2 5 3 2 2 NULL NULL
+1 3 5 3 NULL NULL NULL NULL
+2 2 5 3 NULL NULL NULL NULL
EXPLAIN EXTENDED
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
-FROM t1, t3, t4
+FROM t1, (t3, t4)
RIGHT JOIN
t2
ON t3.a=1 AND t2.b=t4.b
WHERE t1.a <= 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t3` join `test`.`t2` left join `test`.`t4` on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2)
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2)
CREATE INDEX idx_b ON t2(b);
EXPLAIN EXTENDED
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
-FROM t3,t4
+FROM (t3,t4)
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
@@ -874,7 +856,7 @@ id select_type table type possible_keys key key_len ref rows Extra
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t3` join `test`.`t4` left join (`test`.`t1` join `test`.`t2`) on(((`test`.`t3`.`a` = 1) and (`test`.`t3`.`b` = `test`.`t2`.`b`) and (`test`.`t2`.`b` = `test`.`t4`.`b`))) where 1
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
-FROM t3,t4
+FROM (t3,t4)
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
@@ -900,8 +882,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -951,8 +932,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -1001,8 +981,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -1052,8 +1031,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -1100,8 +1078,7 @@ ON t3.a=1 AND t2.b=t4.b,
t5
LEFT JOIN
(
-t6,
-t7
+(t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -1343,3 +1320,58 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 0
1 SIMPLE t3 ALL NULL NULL NULL NULL 0
DROP TABLE t1,t2,t3;
+CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL);
+INSERT INTO t1 VALUES (23, 2340), (26, 9900);
+CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2));
+INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr');
+create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL);
+INSERT INTO t3 VALUES (3,23), (6,26);
+CREATE TABLE t4 (groupid int(12));
+INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6);
+SELECT * FROM
+(SELECT DISTINCT gl.groupid, gp.price
+FROM t4 gl
+LEFT JOIN
+(t3 g INNER JOIN t2 p ON g.goodsid = p.goods
+INNER JOIN t1 gp ON p.goods = gp.goods)
+ON gl.groupid = g.groupid and p.shop = 'fr') t;
+groupid price
+1 NULL
+2 NULL
+3 2340
+4 NULL
+5 NULL
+6 9900
+CREATE VIEW v1 AS
+SELECT g.groupid groupid, p.goods goods,
+p.name name, p.shop shop,
+gp.price price
+FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods
+INNER JOIN t1 gp on p.goods = gp.goods;
+CREATE VIEW v2 AS
+SELECT DISTINCT g.groupid, fr.price
+FROM t4 g
+LEFT JOIN
+v1 fr on g.groupid = fr.groupid and fr.shop = 'fr';
+SELECT * FROM v2;
+groupid price
+1 NULL
+2 NULL
+3 2340
+4 NULL
+5 NULL
+6 9900
+SELECT * FROM
+(SELECT DISTINCT g.groupid, fr.price
+FROM t4 g
+LEFT JOIN
+v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t;
+groupid price
+1 NULL
+2 NULL
+3 2340
+4 NULL
+5 NULL
+6 9900
+DROP VIEW v1,v2;
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index b75eadd5291..d4a20209162 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -106,11 +106,11 @@ grp a c id a c d a
3 6 D 3 6 C 6 6
NULL NULL NULL NULL NULL NULL NULL
explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
-ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions
+ERROR 42S22: Unknown column 't3.a' in 'on clause'
select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
-ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions
+ERROR 42S22: Unknown column 't3.a' in 'on clause'
select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a);
-ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions
+ERROR 42S22: Unknown column 't3.a' in 'on clause'
select t1.*,t2.* from t1 inner join t2 using (a);
grp a c id a c d
1 1 a 1 1 a 1
@@ -124,8 +124,8 @@ grp a c id a c d
3 5 C 3 5 B 5
3 6 D 3 6 C 6
select t1.*,t2.* from t1 natural join t2;
-grp a c id d
-1 1 a 1 1
+grp a c id a c d
+1 1 a 1 1 a 1
drop table t1,t2;
CREATE TABLE t1 (
usr_id INT unsigned NOT NULL,
@@ -400,7 +400,7 @@ insert into t3 values (1);
insert into t4 values (1,1);
insert into t5 values (1,1);
explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23;
-ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions
+ERROR 42S22: Unknown column 't2.t2_id' in 'on clause'
drop table t1,t2,t3,t4,t5;
create table t1 (n int, m int, o int, key(n));
create table t2 (n int not null, m int, o int, primary key(n));
@@ -461,10 +461,10 @@ count color
15 white
7 green
select * from t2 natural join t1;
-count color name
-10 green lime
-7 green lime
-5 black grape
+color count name
+green 10 lime
+green 7 lime
+black 5 grape
select t2.count, t1.name from t2 natural join t1;
count name
10 lime
@@ -647,16 +647,22 @@ insert into t1 values(1),(2);
insert into t2 values(2),(3);
insert into t3 values(2),(4);
select * from t1 natural left join t2 natural left join t3;
-i i i
-1 NULL NULL
-2 2 2
+i
+1
+2
select * from t1 natural left join t2 where (t2.i is not null)=0;
-i i
-1 NULL
+i
+1
select * from t1 natural left join t2 where (t2.i is not null) is not null;
-i i
-1 NULL
-2 2
+i
+1
+2
+select * from t1 natural left join t2 where (i is not null)=0;
+i
+select * from t1 natural left join t2 where (i is not null) is not null;
+i
+1
+2
drop table t1,t2,t3;
create table t1 (f1 integer,f2 integer,f3 integer);
create table t2 (f2 integer,f4 integer);
@@ -664,7 +670,7 @@ create table t3 (f3 integer,f5 integer);
select * from t1
left outer join t2 using (f2)
left outer join t3 using (f3);
-ERROR 42S22: Unknown column 'test.t2.f3' in 'on clause'
+f3 f2 f1 f4 f5
drop table t1,t2,t3;
create table t1 (a1 int, a2 int);
create table t2 (b1 int not null, b2 int);
@@ -941,6 +947,18 @@ aaaaa
bbbbb
Warnings:
Warning 1260 2 line(s) were cut by GROUP_CONCAT()
+select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a;
+group_concat(t1.b,t2.c)
+aaaaa
+bbbbb
+Warnings:
+Warning 1260 2 line(s) were cut by GROUP_CONCAT()
+select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a;
+group_concat(t1.b,t2.c)
+aaaaa
+bbbbb
+Warnings:
+Warning 1260 2 line(s) were cut by GROUP_CONCAT()
drop table t1, t2;
set group_concat_max_len=default;
create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y));
diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result
index b3aa4c5061c..de9a2b2c003 100644
--- a/mysql-test/r/key_cache.result
+++ b/mysql-test/r/key_cache.result
@@ -289,3 +289,9 @@ check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
+set @@global.key_buffer_size=0;
+Warnings:
+Warning 1438 Cannot drop default keycache
+select @@global.key_buffer_size;
+@@global.key_buffer_size
+2097152
diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result
index dcd32bf477b..50b0b6ae294 100644
--- a/mysql-test/r/metadata.result
+++ b/mysql-test/r/metadata.result
@@ -85,3 +85,14 @@ def aaa 1 1 8 20 1 N 32769 0 63
1
1
drop table t1;
+create table t1 (i int);
+insert into t1 values (1),(2),(3);
+select * from t1 where i = 2;
+drop table t1;//
+affected rows: 0
+affected rows: 3
+info: Records: 3 Duplicates: 0 Warnings: 0
+i
+2
+affected rows: 1
+affected rows: 0
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index f5c4e19af64..ea02a703c65 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -135,16 +135,16 @@ create table t1 (n numeric(10));
create table t2 (n numeric(10));
insert into t2 values (1),(2),(4),(8),(16),(32);
select * from t2 left outer join t1 using (n);
-n n
-1 NULL
-2 NULL
-4 NULL
-8 NULL
-16 NULL
-32 NULL
+n
+1
+2
+4
+8
+16
+32
delete t1,t2 from t2 left outer join t1 using (n);
select * from t2 left outer join t1 using (n);
-n n
+n
drop table t1,t2 ;
create table t1 (n int(10) not null primary key, d int(10));
create table t2 (n int(10) not null primary key, d int(10));
diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result
index 6f4d84edef5..ed49e7f3943 100644
--- a/mysql-test/r/ndb_alter_table.result
+++ b/mysql-test/r/ndb_alter_table.result
@@ -179,8 +179,24 @@ a b c
2 two two
alter table t1 drop index c;
select * from t1 where b = 'two';
-ERROR HY000: Table definition has changed, please retry transaction
+a b c
+2 two two
select * from t1 where b = 'two';
a b c
2 two two
drop table t1;
+create table t3 (a int primary key) engine=ndbcluster;
+begin;
+insert into t3 values (1);
+alter table t3 rename t4;
+delete from t3;
+insert into t3 values (1);
+commit;
+select * from t3;
+ERROR HY000: Can't lock file (errno: 155)
+select * from t4;
+a
+1
+drop table t4;
+show tables;
+Tables_in_test
diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result
index 628ca5fd958..6864c35dbfc 100644
--- a/mysql-test/r/order_by.result
+++ b/mysql-test/r/order_by.result
@@ -189,6 +189,15 @@ a b if(b = 1,i,if(b = 2,v,''))
4 2 453 Boardwalk
SELECT a,b,if(b = 1,i,if(b = 2,v,''))
FROM t1
+LEFT JOIN t2 ON t1.c = t2.c
+LEFT JOIN t3 ON t3.c = t1.c;
+a b if(b = 1,i,if(b = 2,v,''))
+1 1 50
+2 1 25
+3 2 123 Park Place
+4 2 453 Boardwalk
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
LEFT JOIN t2 USING(c)
LEFT JOIN t3 ON t3.c = t1.c
ORDER BY a;
@@ -197,6 +206,16 @@ a b if(b = 1,i,if(b = 2,v,''))
2 1 25
3 2 123 Park Place
4 2 453 Boardwalk
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
+LEFT JOIN t2 ON t1.c = t2.c
+LEFT JOIN t3 ON t3.c = t1.c
+ORDER BY a;
+a b if(b = 1,i,if(b = 2,v,''))
+1 1 50
+2 1 25
+3 2 123 Park Place
+4 2 453 Boardwalk
drop table t1,t2,t3;
create table t1 (ID int not null primary key, TransactionID int not null);
insert into t1 (ID, TransactionID) values (1, 87), (2, 89), (3, 92), (4, 94), (5, 486), (6, 490), (7, 753), (9, 828), (10, 832), (11, 834), (12, 840);
@@ -526,9 +545,15 @@ INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug');
SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest
test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug
+SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
+titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest
+test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug
SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest
test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug
+SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
+titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest
+test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug
drop table t1,t2;
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (1, 2);
diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result
index 5d0e1d703a6..16ead200933 100644
--- a/mysql-test/r/ps_2myisam.result
+++ b/mysql-test/r/ps_2myisam.result
@@ -531,44 +531,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -594,44 +594,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -657,23 +657,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result
index da0421d2caa..9ab5a79f755 100644
--- a/mysql-test/r/ps_3innodb.result
+++ b/mysql-test/r/ps_3innodb.result
@@ -531,44 +531,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -594,44 +594,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -657,23 +657,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result
index ff52847a0dc..8336a5bf99b 100644
--- a/mysql-test/r/ps_4heap.result
+++ b/mysql-test/r/ps_4heap.result
@@ -532,44 +532,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -595,44 +595,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -658,23 +658,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result
index 9af8f6ed6ce..f341247a417 100644
--- a/mysql-test/r/ps_5merge.result
+++ b/mysql-test/r/ps_5merge.result
@@ -574,44 +574,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -637,44 +637,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -700,23 +700,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
@@ -3586,44 +3586,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -3649,44 +3649,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -3712,23 +3712,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result
index b7d63b97c09..fe4536827e6 100644
--- a/mysql-test/r/ps_6bdb.result
+++ b/mysql-test/r/ps_6bdb.result
@@ -531,44 +531,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -594,44 +594,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -657,23 +657,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result
index c54c09cf6aa..c4cb92bdc02 100644
--- a/mysql-test/r/ps_7ndb.result
+++ b/mysql-test/r/ps_7ndb.result
@@ -531,44 +531,44 @@ the join statement is:
SELECT * FROM t2 right join t1 using(a) order by t2.a
prepare stmt1 from @query9 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural right join t1 order by t2.a
prepare stmt1 from @query8 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query7 ;
@@ -594,44 +594,44 @@ the join statement is:
SELECT * FROM t2 left join t1 using(a) order by t2.a
prepare stmt1 from @query6 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural left join t1 order by t2.a
prepare stmt1 from @query5 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b
+1 one
+2 two
+3 three
+4 four
the join statement is:
SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
prepare stmt1 from @query4 ;
@@ -657,23 +657,23 @@ the join statement is:
SELECT * FROM t2 join t1 using(a) order by t2.a
prepare stmt1 from @query3 ;
execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
-execute stmt1 ;
-a b a b
-1 one 1 one
-2 two 2 two
-3 three 3 three
-4 four 4 four
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
the join statement is:
SELECT * FROM t2 natural join t1 order by t2.a
prepare stmt1 from @query2 ;
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 6ff49951d27..0efd5ac1566 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -947,24 +947,18 @@ COUNT(*)
Warnings:
Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
-Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid'
-Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid'
SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 invalid';
COUNT(*)
0
Warnings:
Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1
Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1
-Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid'
-Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid'
SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 invalid';
COUNT(*)
0
Warnings:
Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
-Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid'
-Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid'
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
diff --git a/mysql-test/r/query_cache_notembedded.result b/mysql-test/r/query_cache_notembedded.result
index 16a397f78b6..e773a63525b 100644
--- a/mysql-test/r/query_cache_notembedded.result
+++ b/mysql-test/r/query_cache_notembedded.result
@@ -80,4 +80,18 @@ show status like "Qcache_free_blocks";
Variable_name Value
Qcache_free_blocks 1
drop table t1, t2, t3, t11, t21;
+CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE =
+MyISAM;
+LOCK TABLE t1 READ LOCAL;
+INSERT INTO t1 VALUES (), (), ();
+SELECT * FROM t1;
+a
+SELECT * FROM t1;
+a
+1
+2
+3
+SELECT * FROM t1;
+a
+drop table t1;
set GLOBAL query_cache_size=0;
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result
index f7f7e3e8429..1762587415d 100644
--- a/mysql-test/r/row.result
+++ b/mysql-test/r/row.result
@@ -58,7 +58,7 @@ SELECT (1,2,3)=(1,NULL,3);
NULL
SELECT (1,2,3)=(1,NULL,0);
(1,2,3)=(1,NULL,0)
-NULL
+0
SELECT ROW(1,2,3)=ROW(1,2,3);
ROW(1,2,3)=ROW(1,2,3)
1
@@ -175,3 +175,9 @@ ROW(2,10) <=> ROW(3,4)
SELECT ROW(NULL,10) <=> ROW(3,NULL);
ROW(NULL,10) <=> ROW(3,NULL)
0
+SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ;
+1 0 0 0 null
+1 0 0 0 NULL
+select row(NULL,1)=(2,0);
+row(NULL,1)=(2,0)
+0
diff --git a/mysql-test/r/rpl_delete_all.result b/mysql-test/r/rpl_delete_all.result
index 5ed221823e8..1aa556270c9 100644
--- a/mysql-test/r/rpl_delete_all.result
+++ b/mysql-test/r/rpl_delete_all.result
@@ -9,7 +9,7 @@ drop database if exists mysqltest;
Warnings:
Note 1008 Can't drop database 'mysqltest'; database doesn't exist
show tables from mysqltest;
-ERROR HY000: Can't read dir of './mysqltest/' (Errcode: X)
+ERROR 42000: Unknown database 'mysqltest'
create table t1 (a int);
drop table if exists t1;
Warnings:
diff --git a/mysql-test/r/rpl_drop_db.result b/mysql-test/r/rpl_drop_db.result
new file mode 100644
index 00000000000..3d1dfba5b05
--- /dev/null
+++ b/mysql-test/r/rpl_drop_db.result
@@ -0,0 +1,35 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (n int);
+insert into mysqltest.t1 values (1);
+select * from mysqltest.t1 into outfile 'mysqltest/f1.txt';
+create table mysqltest.t2 (n int);
+create table mysqltest.t3 (n int);
+drop database mysqltest;
+ERROR HY000: Error dropping database (can't rmdir './mysqltest/', errno: 17)
+use mysqltest;
+show tables;
+Tables_in_mysqltest
+drop database mysqltest;
+ERROR HY000: Error dropping database (can't rmdir './mysqltest/', errno: 17)
+use mysqltest;
+show tables;
+Tables_in_mysqltest
+use test;
+create table t1 (n int);
+insert into t1 values (1234);
+use mysqltest;
+show tables;
+Tables_in_mysqltest
+use test;
+select * from t1;
+n
+1234
+drop table t1;
+stop slave;
diff --git a/mysql-test/r/rpl_insert_select.result b/mysql-test/r/rpl_insert_select.result
new file mode 100644
index 00000000000..1aff39e0026
--- /dev/null
+++ b/mysql-test/r/rpl_insert_select.result
@@ -0,0 +1,17 @@
+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;
+create table t1 (n int not null primary key);
+insert into t1 values (1);
+create table t2 (n int);
+insert into t2 values (1);
+insert ignore into t1 select * from t2;
+insert into t1 values (2);
+select * from t1;
+n
+1
+2
+drop table t1,t2;
diff --git a/mysql-test/r/rpl_openssl.result b/mysql-test/r/rpl_openssl.result
index a4ed922d9d4..d916e9f2c5c 100644
--- a/mysql-test/r/rpl_openssl.result
+++ b/mysql-test/r/rpl_openssl.result
@@ -4,7 +4,7 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-grant replication slave on *.* to replssl@'%' require ssl;
+grant replication slave on *.* to replssl@localhost require ssl;
create table t1 (t int);
stop slave;
change master to master_user='replssl',master_password='';
@@ -20,11 +20,11 @@ t
1
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 replssl MASTER_MYPORT 1 master-bin.000001 392 # # master-bin.000001 Yes Yes 0 0 392 # None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
+# 127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 398 # # master-bin.000001 Yes Yes 0 0 398 # None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
stop slave;
change master to master_user='root',master_password='', master_ssl=0;
start slave;
drop table t1;
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 468 # # master-bin.000001 Yes Yes 0 0 468 # None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 474 # # master-bin.000001 Yes Yes 0 0 474 # None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result
index 15180abe8fd..b31951e93c5 100644
--- a/mysql-test/r/rpl_sp.result
+++ b/mysql-test/r/rpl_sp.result
@@ -109,6 +109,7 @@ call foo4();
Got one of the listed errors
show warnings;
Level Code Message
+Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
call foo3();
show warnings;
@@ -117,6 +118,7 @@ call foo4();
Got one of the listed errors
show warnings;
Level Code Message
+Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
alter procedure foo4 sql security invoker;
call foo4();
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result
new file mode 100644
index 00000000000..db824c9c423
--- /dev/null
+++ b/mysql-test/r/rpl_trigger.result
@@ -0,0 +1,108 @@
+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;
+create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null);
+create table t2 (a int auto_increment, primary key (a), b int);
+create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null);
+create trigger t1 before insert on t1 for each row
+begin
+insert into t3 values (NULL, "t1", new.a, new.b, rand());
+end|
+create trigger t2 after insert on t2 for each row
+begin
+insert into t3 values (NULL, "t2", new.a, new.b, rand());
+end|
+insert into t3 values(100,"log",0,0,0);
+SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
+insert into t1 values(1,1,rand()),(NULL,2,rand());
+insert into t2 (b) values(last_insert_id());
+insert into t2 values(3,0),(NULL,0);
+insert into t2 values(NULL,0),(500,0);
+select a,b, truncate(rand_value,4) from t1;
+a b truncate(rand_value,4)
+1 1 0.4320
+2 2 0.3055
+select * from t2;
+a b
+1 2
+3 0
+4 0
+5 0
+500 0
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+a name old_a old_b truncate(rand_value,4)
+100 log 0 0 0.0000
+101 t1 1 1 0.3203
+102 t1 0 2 0.5666
+103 t2 1 2 0.9164
+104 t2 3 0 0.8826
+105 t2 4 0 0.6635
+106 t2 5 0 0.6699
+107 t2 500 0 0.3593
+
+--- On slave --
+select a,b, truncate(rand_value,4) from t1;
+a b truncate(rand_value,4)
+1 1 0.4320
+2 2 0.3055
+select * from t2;
+a b
+1 2
+3 0
+4 0
+5 0
+500 0
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+a name old_a old_b truncate(rand_value,4)
+100 log 0 0 0.0000
+101 t1 1 1 0.3203
+102 t1 0 2 0.5666
+103 t2 1 2 0.9164
+104 t2 3 0 0.8826
+105 t2 4 0 0.6635
+106 t2 5 0 0.6699
+107 t2 500 0 0.3593
+drop table t1,t2,t3;
+select get_lock("bug12480",2);
+get_lock("bug12480",2)
+1
+create table t1 (a datetime,b datetime, c datetime);
+drop function if exists bug12480;
+Warnings:
+Note 1305 FUNCTION bug12480 does not exist
+create function bug12480() returns datetime
+begin
+set @a=get_lock("bug12480",2);
+return now();
+end|
+create trigger t1_first before insert on t1
+for each row begin
+set @a=get_lock("bug12480",2);
+set new.b= now();
+set new.c= bug12480();
+end
+|
+insert into t1 set a = now();
+select a=b && a=c from t1;
+a=b && a=c
+1
+
+--- On slave --
+select a=b && a=c from t1;
+a=b && a=c
+1
+test
+1
+truncate table t1;
+drop trigger t1_first;
+insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now());
+select a=b && a=c from t1;
+a=b && a=c
+1
+1
+1
+drop function bug12480;
+drop table t1;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index a0f6bb7084f..83682d87504 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -1364,6 +1364,17 @@ explain select t2.companynr,companyname from t4 left join t2 using (companynr) w
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists
+select companynr,companyname from t2 left join t4 using (companynr) where companynr is null;
+companynr companyname
+select count(*) from t2 left join t4 using (companynr) where companynr is not null;
+count(*)
+1200
+explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
delete from t2 where fld1=999999;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra
@@ -1377,6 +1388,18 @@ explain select t2.companynr,companyname from t4 left join t2 using (companynr) w
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
@@ -1389,6 +1412,18 @@ explain select t2.companynr,companyname from t4 left join t2 using (companynr) w
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
+explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
companynr companynr
37 36
@@ -2115,159 +2150,159 @@ insert into t1 values ();
insert into t1 values ();
insert into t1 values ();
select * from (t1 as t2 left join t1 as t3 using (a)), t1;
-a a a
-1 1 1
-2 2 1
-3 3 1
-1 1 2
-2 2 2
-3 3 2
-1 1 3
-2 2 3
-3 3 3
+a a
+1 1
+2 1
+3 1
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from t1, (t1 as t2 left join t1 as t3 using (a));
-a a a
-1 1 1
-2 1 1
-3 1 1
-1 2 2
-2 2 2
-3 2 2
-1 3 3
-2 3 3
-3 3 3
+a a
+1 1
+2 1
+3 1
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from (t1 as t2 left join t1 as t3 using (a)) straight_join t1;
-a a a
-1 1 1
-2 2 1
-3 3 1
-1 1 2
-2 2 2
-3 3 2
-1 1 3
-2 2 3
-3 3 3
+a a
+1 1
+2 1
+3 1
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from t1 straight_join (t1 as t2 left join t1 as t3 using (a));
-a a a
-1 1 1
-2 1 1
-3 1 1
-1 2 2
-2 2 2
-3 2 2
-1 3 3
-2 3 3
-3 3 3
+a a
+1 1
+2 1
+3 1
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1;
-a a a
-1 1 2
-2 2 2
-3 3 2
-1 1 3
-2 2 3
-3 3 3
+a a
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
-a a a
-2 1 1
-3 1 1
-2 2 2
-3 2 2
-2 3 3
-3 3 3
+a a
+2 1
+3 1
+2 2
+3 2
+2 3
+3 3
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
-a a a
-1 1 2
-1 1 3
-2 2 2
-2 2 3
-3 3 2
-3 3 3
+a a
+1 2
+1 3
+2 2
+2 3
+3 2
+3 3
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
-a a a
-1 NULL NULL
-2 1 1
-2 2 2
-2 3 3
-3 1 1
-3 2 2
-3 3 3
+a a
+1 NULL
+2 1
+2 2
+2 3
+3 1
+3 2
+3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a));
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
-a a a
-NULL NULL 1
-1 1 2
-2 2 2
-3 3 2
-1 1 3
-2 2 3
-3 3 3
+a a
+NULL 1
+1 2
+2 2
+3 2
+1 3
+2 3
+3 3
select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
-a a a
-2 1 1
-3 1 1
-2 2 2
-3 2 2
-2 3 3
-3 3 3
+a a
+2 1
+3 1
+2 2
+3 2
+2 3
+3 3
select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1;
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
-a a a
-1 1 1
-2 2 2
-3 3 3
+a
+1
+2
+3
select * from t1 natural join (t1 as t2 left join t1 as t3 using (a));
-a a
-1 1
-2 2
-3 3
+a
+1
+2
+3
select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1;
-a a
-1 1
-2 2
-3 3
+a
+1
+2
+3
drop table t1;
CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522);
@@ -2759,3 +2794,96 @@ DROP TABLE t1,t2;
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0
16 16 2 2
+create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null);
+create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4));
+insert into t1 values (" 2", 2);
+insert into t2 values (" 2", " one "),(" 2", " two ");
+select * from t1 left join t2 on f1 = f3;
+f1 f2 f3 f4
+ 2 2 2 one
+ 2 2 2 two
+drop table t1,t2;
+create table t1 (empnum smallint, grp int);
+create table t2 (empnum int, name char(5));
+insert into t1 values(1,1);
+insert into t2 values(1,'bob');
+create view v1 as select * from t2 inner join t1 using (empnum);
+select * from v1;
+empnum name grp
+1 bob 1
+drop table t1,t2;
+drop view v1;
+create table t1 (pk int primary key, b int);
+create table t2 (pk int primary key, c int);
+select pk from t1 inner join t2 using (pk);
+pk
+drop table t1,t2;
+create table t1 (s1 int, s2 char(5), s3 decimal(10));
+create view v1 as select s1, s2, 'x' as s3 from t1;
+select * from t1 natural join v1;
+s1 s2 s3
+insert into t1 values (1,'x',5);
+select * from t1 natural join v1;
+s1 s2 s3
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'x'
+drop table t1;
+drop view v1;
+create table t1(a1 int);
+create table t2(a2 int);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+create view v2 (c) as select a1 from t1;
+select * from t1 natural left join t2;
+a1 a2
+1 1
+1 2
+2 1
+2 2
+select * from t1 natural right join t2;
+a2 a1
+1 1
+1 2
+2 1
+2 2
+select * from v2 natural left join t2;
+c a2
+1 1
+1 2
+2 1
+2 2
+select * from v2 natural right join t2;
+a2 c
+1 1
+1 2
+2 1
+2 2
+drop table t1, t2;
+drop view v2;
+create table t1 (a int(10), t1_val int(10));
+create table t2 (b int(10), t2_val int(10));
+create table t3 (a int(10), b int(10));
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2),(3,3);
+insert into t3 values (1,1),(2,1),(3,1),(4,1);
+select * from t1 natural join t2 natural join t3;
+a b t1_val t2_val
+1 1 1 1
+2 1 2 1
+select * from t1 natural join t3 natural join t2;
+b a t1_val t2_val
+1 1 1 1
+1 2 2 1
+drop table t1, t2, t3;
+create table t1 (a char(1));
+create table t2 (a char(1));
+insert into t1 values ('a'),('b'),('c');
+insert into t2 values ('b'),('c'),('d');
+select a from t1 natural join t2;
+a
+b
+c
+select * from t1 natural join t2 where a = 'b';
+a
+b
+drop table t1, t2;
diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result
index 5d458c40f34..feac9efcb13 100644
--- a/mysql-test/r/select_safe.result
+++ b/mysql-test/r/select_safe.result
@@ -84,7 +84,7 @@ set local max_join_size=8;
select * from (select * from t1) x;
ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
set local max_join_size=1;
-select * from (select * from t1 a, t1 b) x;
+select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x;
ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
set local max_join_size=1;
select * from (select 1 union select 2 union select 3) x;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index f1c536ed1da..c143c7f0f29 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -512,3 +512,48 @@ t1 CREATE TABLE `t1` (
KEY `c2` USING BTREE (`c2`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
+CREATE TABLE txt1(a int);
+CREATE TABLE tyt2(a int);
+CREATE TABLE urkunde(a int);
+FLUSH TABLES;
+SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0;
+1
+SHOW OPEN TABLES;
+Database Table In_use Name_locked
+mysql db 0 0
+test urkunde 0 0
+mysql time_zone 0 0
+mysql user 0 0
+test txt1 0 0
+mysql proc 0 0
+test tyt2 0 0
+mysql time_zone_name 0 0
+SHOW OPEN TABLES FROM mysql;
+Database Table In_use Name_locked
+mysql db 0 0
+mysql time_zone 0 0
+mysql user 0 0
+mysql proc 0 0
+mysql time_zone_name 0 0
+SHOW OPEN TABLES FROM mysql LIKE 'u%';
+Database Table In_use Name_locked
+mysql user 0 0
+SHOW OPEN TABLES LIKE 't%';
+Database Table In_use Name_locked
+mysql time_zone 0 0
+test txt1 0 0
+test tyt2 0 0
+mysql time_zone_name 0 0
+SHOW OPEN TABLES LIKE '%o%';
+Database Table In_use Name_locked
+mysql time_zone 0 0
+mysql proc 0 0
+mysql time_zone_name 0 0
+FLUSH TABLES;
+SHOW OPEN TABLES;
+Database Table In_use Name_locked
+DROP TABLE txt1;
+DROP TABLE tyt2;
+DROP TABLE urkunde;
+SHOW TABLES FROM non_existing_database;
+ERROR 42000: Unknown database 'non_existing_database'
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 13f46e507ba..4ac29a07757 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -247,7 +247,7 @@ end|
ERROR 42000: Duplicate cursor: c
create procedure u()
use sptmp|
-ERROR 42000: USE is not allowed in a stored procedure
+ERROR 0A000: USE is not allowed in stored procedures
create procedure p()
begin
declare c cursor for select * from t1;
@@ -299,6 +299,36 @@ lock tables t1 read, mysql.proc read|
unlock tables|
lock tables mysql.proc write|
unlock tables|
+drop function if exists f1|
+create function f1(i int) returns int
+begin
+insert into t1 (val) values (i);
+return 0;
+end|
+select val, f1(val) from t1|
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select val, f1(val) from t1 as tab|
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select * from t1|
+val x
+42 3.1
+19 1.2
+update t1 set val= f1(val)|
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select * from t1|
+val x
+42 3.1
+19 1.2
+select f1(17)|
+f1(17)
+0
+select * from t1|
+val x
+42 3.1
+19 1.2
+17 NULL
+delete from t1 where val= 17|
+drop function f1|
create procedure bug1965()
begin
declare c cursor for select val from t1 order by valname;
@@ -616,7 +646,7 @@ begin
flush tables;
return 5;
end|
-ERROR 0A000: FLUSH is not allowed in stored procedures
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123()
begin
end|
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index 184978e4a0d..eb2e2ce334e 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -236,3 +236,18 @@ drop procedure bug7291_2;
drop procedure bug7291_0;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop user user1@localhost;
+drop database if exists mysqltest_1;
+create database mysqltest_1;
+create procedure mysqltest_1.p1()
+begin
+select 1 from dual;
+end//
+grant usage on *.* to mysqltest_1@localhost;
+call mysqltest_1.p1();
+ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1'
+call mysqltest_1.p1();
+ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1'
+drop procedure mysqltest_1.p1;
+drop database mysqltest_1;
+revoke usage on *.* from mysqltest_1@localhost;
+drop user mysqltest_1@localhost;
diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result
index 2f7e8021aa7..c516d7a643f 100644
--- a/mysql-test/r/sp-threads.result
+++ b/mysql-test/r/sp-threads.result
@@ -37,6 +37,7 @@ Id User Host db Command Time State Info
# 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
+# root localhost test Sleep # NULL
unlock tables;
drop procedure bug9486;
drop table t1, t2;
@@ -64,3 +65,27 @@ insert into t1 (select f from v1);
drop function bug11554;
drop table t1;
drop view v1;
+drop procedure if exists p1;
+drop procedure if exists p2;
+create table t1 (s1 int)|
+create procedure p1() select * from t1|
+create procedure p2()
+begin
+insert into t1 values (1);
+call p1();
+select * from t1;
+end|
+use test;
+lock table t1 write;
+ call p2();
+use test;
+drop procedure p1;
+create procedure p1() select * from t1;
+unlock tables;
+s1
+1
+s1
+1
+drop procedure p1;
+drop procedure p2;
+drop table t1;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index e04f8fce5c4..423cd546a84 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -3076,4 +3076,95 @@ v1 v2 v3 v4 v5 v6 v7
NULL
drop procedure bug8692|
drop table t3|
+drop function if exists bug10055|
+create function bug10055(v char(255)) returns char(255) return lower(v)|
+select t.column_name, bug10055(t.column_name)
+from information_schema.columns as t
+where t.table_schema = 'test' and t.table_name = 't1'|
+column_name bug10055(t.column_name)
+id id
+data data
+drop function bug10055|
+drop function if exists f_bug11247|
+drop procedure if exists p_bug11247|
+create function f_bug11247(param int)
+returns int
+return param + 1|
+create procedure p_bug11247(lim int)
+begin
+declare v int default 0;
+while v < lim do
+set v= f_bug11247(v);
+end while;
+end|
+call p_bug11247(10)|
+drop function f_bug11247|
+drop procedure p_bug11247|
+drop procedure if exists bug12168|
+drop table if exists t3, t4|
+create table t3 (a int)|
+insert into t3 values (1),(2),(3),(4)|
+create table t4 (a int)|
+create procedure bug12168(arg1 char(1))
+begin
+declare b, c integer;
+if arg1 = 'a' then
+begin
+declare c1 cursor for select a from t3 where a % 2;
+declare continue handler for not found set b = 1;
+set b = 0;
+open c1;
+c1_repeat: repeat
+fetch c1 into c;
+if (b = 1) then
+leave c1_repeat;
+end if;
+insert into t4 values (c);
+until b = 1
+end repeat;
+end;
+end if;
+if arg1 = 'b' then
+begin
+declare c2 cursor for select a from t3 where not a % 2;
+declare continue handler for not found set b = 1;
+set b = 0;
+open c2;
+c2_repeat: repeat
+fetch c2 into c;
+if (b = 1) then
+leave c2_repeat;
+end if;
+insert into t4 values (c);
+until b = 1
+end repeat;
+end;
+end if;
+end|
+call bug12168('a')|
+select * from t4|
+a
+1
+3
+truncate t4|
+call bug12168('b')|
+select * from t4|
+a
+2
+4
+truncate t4|
+call bug12168('a')|
+select * from t4|
+a
+1
+3
+truncate t4|
+call bug12168('b')|
+select * from t4|
+a
+2
+4
+truncate t4|
+drop table t3, t4|
+drop procedure if exists bug12168|
drop table t1,t2;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index bbca9c905df..14806279362 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -923,7 +923,7 @@ select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a') (select c from t1 where a=t2.a)
1 1 a
2 0 b
-NULL NULL NULL
+NULL 0 NULL
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2;
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b') (select c from t1 where a=t2.a)
1 0 a
@@ -933,7 +933,7 @@ select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where a=t2.a)
1 0 a
2 0 b
-NULL NULL NULL
+NULL 0 NULL
drop table t1,t2;
create table t1 (a int, b real, c varchar(10));
insert into t1 values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b');
@@ -942,7 +942,7 @@ ROW(1, 1, 'a') IN (select a,b,c from t1)
1
select ROW(1, 2, 'a') IN (select a,b,c from t1);
ROW(1, 2, 'a') IN (select a,b,c from t1)
-NULL
+0
select ROW(1, 1, 'a') IN (select b,a,c from t1);
ROW(1, 1, 'a') IN (select b,a,c from t1)
1
@@ -960,7 +960,7 @@ ROW(1, 1, 'a') IN (select a,b,c from t1 where c='b' or c='a')
1
select ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a');
ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a')
-NULL
+0
select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a');
ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a')
1
@@ -1200,7 +1200,7 @@ INSERT INTO t1 VALUES (1);
UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i));
UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i));
UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t);
-ERROR 42S02: Unknown table 't' in field list
+ERROR 42S22: Unknown column 't.i' in 'field list'
select * from t1;
i
1
@@ -1638,7 +1638,7 @@ ERROR 42S22: Unknown column 't1.s2' in 'where clause'
select * from t1 where (select count(*) from t2 group by t1.s2) = 1;
ERROR 42S22: Unknown column 't1.s2' in 'group statement'
select count(*) from t2 group by t1.s2;
-ERROR 42S02: Unknown table 't1' in group statement
+ERROR 42S22: Unknown column 't1.s2' in 'group statement'
drop table t1, t2;
CREATE TABLE t1(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC VARCHAR(20) DEFAULT NULL,PRIMARY KEY (COLA, COLB));
CREATE TABLE t2(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC CHAR(1) NOT NULL,PRIMARY KEY (COLA));
@@ -1793,10 +1793,18 @@ SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t
id c
1 1
2 0
+SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id);
+id c
+1 1
+2 0
SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id;
id c
1 1
2 0
+SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id;
+id c
+1 1
+2 0
DROP TABLE t1,t2;
CREATE TABLE t1 ( a int, b int );
INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
@@ -2709,7 +2717,143 @@ select (1,2,3) = (select * from t1);
ERROR 21000: Operand should contain 3 column(s)
select (select * from t1) = (1,2,3);
ERROR 21000: Operand should contain 2 column(s)
+drop table t1
+#;
+CREATE TABLE `t1` (
+`itemid` bigint(20) unsigned NOT NULL auto_increment,
+`sessionid` bigint(20) unsigned default NULL,
+`time` int(10) unsigned NOT NULL default '0',
+`type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT
+NULL default '',
+`data` text collate latin1_general_ci NOT NULL,
+PRIMARY KEY (`itemid`)
+) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+INSERT INTO `t1` VALUES (1, 1, 1, 'D', '');
+CREATE TABLE `t2` (
+`sessionid` bigint(20) unsigned NOT NULL auto_increment,
+`pid` int(10) unsigned NOT NULL default '0',
+`date` int(10) unsigned NOT NULL default '0',
+`ip` varchar(15) collate latin1_general_ci NOT NULL default '',
+PRIMARY KEY (`sessionid`)
+) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1');
+SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30;
+ip count( e.itemid )
+10.10.10.1 1
+drop tables t1,t2;
+create table t1 (fld enum('0','1'));
+insert into t1 values ('1');
+select * from (select max(fld) from t1) as foo;
+max(fld)
+1
drop table t1;
+CREATE TABLE t1 (one int, two int, flag char(1));
+CREATE TABLE t2 (one int, two int, flag char(1));
+INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N');
+INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N');
+SELECT * FROM t1
+WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N');
+one two flag
+5 6 N
+7 8 N
+SELECT * FROM t1
+WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N');
+one two flag
+5 6 N
+7 8 N
+insert into t2 values (null,null,'N');
+insert into t2 values (null,3,'0');
+insert into t2 values (null,5,'0');
+insert into t2 values (10,null,'0');
+insert into t1 values (10,3,'0');
+insert into t1 values (10,5,'0');
+insert into t1 values (10,10,'0');
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1;
+one two test
+1 2 NULL
+2 3 NULL
+3 4 NULL
+5 6 1
+7 8 1
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+one two
+5 6
+7 8
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1;
+one two test
+1 2 NULL
+2 3 NULL
+3 4 NULL
+5 6 1
+7 8 1
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+one two test
+1 2 0
+2 3 NULL
+3 4 0
+5 6 0
+7 8 0
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+one two test
+1 2 0
+2 3 NULL
+3 4 0
+5 6 0
+7 8 0
+10 3 NULL
+10 5 NULL
+10 10 NULL
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = _latin1'0') and ((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`)) and ((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) having (<is_not_null_test>(`test`.`t2`.`one`) and <is_not_null_test>(`test`.`t2`.`two`)))) AS `test` from `test`.`t1`
+explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = _latin1'N') and (<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) and (<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`))))
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort
+Warnings:
+Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where (`test`.`t2`.`flag` = _latin1'0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`)) and ((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)) and <is_not_null_test>(`test`.`t2`.`one`) and <is_not_null_test>(`test`.`t2`.`two`)))) AS `test` from `test`.`t1`
+DROP TABLE t1,t2;
+CREATE TABLE t1 (a char(5), b char(5));
+INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa');
+SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb'));
+a b
+aaa aaa
+DROP TABLE t1;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int, b int);
+CREATE TABLE t3 (b int NOT NULL);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (1,10), (3,30);
+SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+WHERE t3.b IS NOT NULL OR t2.a > 10;
+a b b
+SELECT * FROM t1
+WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+WHERE t3.b IS NOT NULL OR t2.a > 10);
+a
+1
+2
+3
+4
+DROP TABLE t1,t2,t3;
create table t1 (df decimal(5,1));
insert into t1 values(1.1);
insert into t1 values(2.2);
diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result
index 210ac0a8cc3..bc902ea7b0f 100644
--- a/mysql-test/r/subselect2.result
+++ b/mysql-test/r/subselect2.result
@@ -120,8 +120,8 @@ DOCID DOCNAME DOCTYPEID FOLDERID AUTHOR CREATED TITLE SUBTITLE DOCABSTRACT PUBLI
c373e9f5ad07993f3859444553544200 Last Discussion c373e9f5ad079174ff17444553544200 c373e9f5ad0796c0eca4444553544200 Goldilocks 2003-06-09 11:21:06 Title: Last Discussion NULL Setting new abstract and keeping doc checked out 2003-06-09 10:51:26 2003-06-09 10:51:26 NULL NULL NULL 03eea05112b845949f3fd03278b5fe43 2003-06-09 11:21:06 admin 0 NULL Discussion NULL NULL
EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 system PRIMARY NULL NULL NULL 0 const row not found
1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where
+1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1
2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 52bf307a686..312a7a90fc9 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -2,6 +2,7 @@ drop table if exists t1, t2, t3;
drop view if exists v1;
drop database if exists mysqltest;
drop function if exists f1;
+drop procedure if exists p1;
create table t1 (i int);
create trigger trg before insert on t1 for each row set @a:=1;
set @a:=0;
@@ -635,3 +636,105 @@ show triggers;
Trigger Event Table Statement Timing Created sql_mode
t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE #
drop table t1;
+create table t1 (id int);
+create trigger t1_ai after insert on t1 for each row flush tables;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush privileges;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create procedure p1() flush tables;
+create trigger t1_ai after insert on t1 for each row call p1();
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush privileges;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+drop table t1;
+create table t1 (id int, data int, username varchar(16));
+insert into t1 (id, data) values (1, 0);
+create trigger t1_whoupdated before update on t1 for each row
+begin
+declare user varchar(32);
+declare i int;
+select user() into user;
+set NEW.username = user;
+select count(*) from ((select 1) union (select 2)) as d1 into i;
+end|
+update t1 set data = 1;
+update t1 set data = 2;
+drop table t1;
+create table t1 (c1 int, c2 datetime);
+create trigger tr1 before insert on t1 for each row
+begin
+set new.c2= '2004-04-01';
+select 'hello';
+end|
+ERROR 0A000: Not allowed to return a result set from a trigger
+insert into t1 (c1) values (1),(2),(3);
+select * from t1;
+c1 c2
+1 NULL
+2 NULL
+3 NULL
+drop procedure if exists bug11587;
+create procedure bug11587(x char(16))
+begin
+select "hello";
+select "hello again";
+end|
+create trigger tr1 before insert on t1 for each row
+begin
+call bug11587();
+set new.c2= '2004-04-02';
+end|
+insert into t1 (c1) values (4),(5),(6);
+ERROR 0A000: PROCEDURE test.bug11587 can't return a result set in the given context
+select * from t1;
+c1 c2
+1 NULL
+2 NULL
+3 NULL
+drop procedure bug11587;
+drop table t1;
+create table t1 (f1 integer);
+create table t2 (f2 integer);
+create trigger t1_ai after insert on t1
+for each row insert into t2 values (new.f1+1);
+create trigger t2_ai after insert on t2
+for each row insert into t1 values (new.f2+1);
+insert into t1 values (1);
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select * from t1;
+f1
+1
+select * from t2;
+f2
+2
+drop trigger t1_ai;
+drop trigger t2_ai;
+create trigger t1_bu before update on t1
+for each row insert into t1 values (2);
+update t1 set f1= 10;
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select * from t1;
+f1
+1
+drop trigger t1_bu;
+create trigger t1_bu before update on t1
+for each row delete from t1 where f1=new.f1;
+update t1 set f1= 10;
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+select * from t1;
+f1
+1
+drop trigger t1_bu;
+create trigger t1_bi before insert on t1
+for each row set new.f1=(select sum(f1) from t1);
+insert into t1 values (3);
+select * from t1;
+f1
+1
+1
+drop trigger t1_bi;
+drop tables t1, t2;
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
index 4aa8587d6e1..5988b4f745e 100644
--- a/mysql-test/r/type_bit.result
+++ b/mysql-test/r/type_bit.result
@@ -34,9 +34,9 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001';
0 + b'1000000000000001'
32769
-drop table if exists t1;
+drop table if exists t1,t2;
create table t1 (a bit(65));
-ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead
+ERROR 42000: Display width out of range for column 'a' (max = 64)
create table t1 (a bit(0));
show create table t1;
Table Create Table
diff --git a/mysql-test/r/type_bit_innodb.result b/mysql-test/r/type_bit_innodb.result
index f3e9dad3baa..8d9c9756a33 100644
--- a/mysql-test/r/type_bit_innodb.result
+++ b/mysql-test/r/type_bit_innodb.result
@@ -36,7 +36,7 @@ select 0 + b'1000000000000001';
32769
drop table if exists t1;
create table t1 (a bit(65)) engine=innodb;
-ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead
+ERROR 42000: Display width out of range for column 'a' (max = 64)
create table t1 (a bit(0)) engine=innodb;
show create table t1;
Table Create Table
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 788478de77e..85f899be5d8 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -26,6 +26,8 @@ Table Op Msg_type Msg_text
test.t1 check status OK
delete from t1;
insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000");
+insert into t1 values ("2003-003-03");
+insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01");
select * from t1;
t
2000-01-01 00:00:00
@@ -43,6 +45,17 @@ t
9999-12-31 23:59:59
2003-01-00 00:00:00
2003-00-00 00:00:00
+2003-03-03 00:00:00
+2003-01-02 13:14:15
+2001-01-01 01:01:01
+2001-01-01 01:01:01
+truncate table t1;
+insert into t1 values("2003-0303 12:13:14");
+Warnings:
+Warning 1264 Out of range value adjusted for column 't' at row 1
+select * from t1;
+t
+0000-00-00 00:00:00
drop table t1;
CREATE TABLE t1 (a timestamp, b date, c time, d datetime);
insert into t1 (b,c,d) values(now(),curtime(),now());
@@ -153,13 +166,3 @@ dt
0000-00-00 00:00:00
0000-00-00 00:00:00
drop table t1;
-create table t1 (dt datetime);
-insert into t1 values ("20010101T010101");
-insert into t1 values ("2001-01-01T01:01:01");
-insert into t1 values ("2001-1-1T1:01:01");
-select * from t1;
-dt
-2001-01-01 01:01:01
-2001-01-01 01:01:01
-2001-01-01 01:01:01
-drop table t1;
diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result
index 3da8d76e0f2..1342603f755 100644
--- a/mysql-test/r/type_ranges.result
+++ b/mysql-test/r/type_ranges.result
@@ -311,16 +311,32 @@ select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
id_A id_B
1 1
2 NULL
+select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
+id_A id_B
+1 1
+2 NULL
create table t3 (id_A integer unsigned not null, id_B integer unsigned null );
insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
select * from t3;
id_A id_B
1 1
2 NULL
+delete from t3;
+insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
+select * from t3;
+id_A id_B
+1 1
+2 NULL
drop table t3;
create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
select * from t3;
id_A id_B
1 1
2 NULL
+drop table t3;
+create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
+select * from t3;
+id_A id_B
+1 1
+2 NULL
drop table t1,t2,t3;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 1f45d238ea5..eb129e32983 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -430,7 +430,7 @@ drop temporary table t1;
create table t1 select a from t1 union select a from t2;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
select a from t1 union select a from t2 order by t2.a;
-ERROR 42S02: Unknown table 't2' in order clause
+ERROR 42S22: Unknown column 't2.a' in 'order clause'
drop table t1,t2;
select length(version()) > 1 as `*` UNION select 2;
*
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index f6b5018cf3a..7aa41137b05 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -6,7 +6,7 @@ create view v1 (c,d) as select a,b from t1;
ERROR 42S02: Table 'test.t1' doesn't exist
create temporary table t1 (a int, b int);
create view v1 (c) as select b+1 from t1;
-ERROR HY000: View's SELECT contains a temporary table 't1'
+ERROR HY000: View's SELECT refers to a temporary table 't1'
drop table t1;
create table t1 (a int, b int);
insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
@@ -150,12 +150,12 @@ v6 VIEW
show table status;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t1 MyISAM 10 Fixed 5 9 45 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
-v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
-v2 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
-v3 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
-v4 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
-v5 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
-v6 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
+v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
+v2 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
+v3 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
+v4 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
+v5 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
+v6 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL VIEW
drop view v1,v2,v3,v4,v5,v6;
create view v1 (c,d,e,f) as select a,b,
a in (select a+2 from t1), a = all (select a from t1) from t1;
@@ -1880,6 +1880,8 @@ test.v5 check error View 'test.v5' references invalid table(s) or column(s) or f
test.v6 check status OK
drop view v1, v2, v3, v4, v5, v6;
drop table t2;
+drop function if exists f1;
+drop function if exists f2;
CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time);
@@ -2063,3 +2065,65 @@ pid GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1)
2 c d
DROP VIEW v1;
DROP TABLE t1,t2;
+CREATE TABLE t1 (id int PRIMARY KEY, f varchar(255));
+CREATE VIEW v1 AS SELECT id, f FROM t1 WHERE id <= 2;
+INSERT INTO t1 VALUES (2, 'foo2');
+INSERT INTO t1 VALUES (1, 'foo1');
+SELECT * FROM v1;
+id f
+1 foo1
+2 foo2
+SELECT * FROM v1;
+id f
+1 foo1
+2 foo2
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (pk int PRIMARY KEY, b int);
+CREATE TABLE t2 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t3 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t4 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t5 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE VIEW v1 AS
+SELECT t1.pk as a FROM t1,t2,t3,t4,t5
+WHERE t1.b IS NULL AND
+t1.pk=t2.fk AND t2.pk=t3.fk AND t3.pk=t4.fk AND t4.pk=t5.fk;
+SELECT a FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1,t2,t3,t4,t5;
+create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1;
+select * from v1;
+f1
+1
+drop view v1;
+create table t1 (f1 int);
+create table t2 (f1 int);
+insert into t1 values (1);
+insert into t2 values (2);
+create view v1 as select * from t1 union select * from t2 union all select * from t2;
+select * from v1;
+f1
+1
+2
+2
+drop view v1;
+drop table t1,t2;
+CREATE TEMPORARY TABLE t1 (a int);
+CREATE FUNCTION f1 () RETURNS int RETURN (SELECT COUNT(*) FROM t1);
+CREATE VIEW v1 AS SELECT f1();
+ERROR HY000: View's SELECT refers to a temporary table 't1'
+DROP FUNCTION f1;
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+CREATE TABLE t1 (f4 CHAR(5));
+CREATE VIEW v1 AS SELECT * FROM t1;
+DESCRIBE v1;
+Field Type Null Key Default Extra
+f4 char(5) YES NULL
+ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5);
+DESCRIBE v1;
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+DROP TABLE t1;
+DROP VIEW v1;
diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result
index 1dde495d6ae..f3d7e151628 100644
--- a/mysql-test/r/xa.result
+++ b/mysql-test/r/xa.result
@@ -22,6 +22,8 @@ a
xa start 'testa','testb';
insert t1 values (30);
xa end 'testa','testb';
+xa start 'testa','testb';
+ERROR XAE08: XAER_DUPID: The XID already exists
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
xa end 'testb',' 0@P`',11;
@@ -35,11 +37,11 @@ formatID gtrid_length bqual_length data
11 5 5 testb 0@P`
1 5 5 testatestb
xa commit 'testb',0x2030405060,11;
+ERROR XAE04: XAER_NOTA: Unknown XID
xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
select * from t1;
a
20
-40
drop table t1;
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index c1abe011be4..3167682f816 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -401,6 +401,7 @@ set @a:=now();
CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=bdb;
insert into t1 (a) values(1),(2),(3);
select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a;
+select a from t1 natural join t1 as t2 where b >= @a order by a;
update t1 set a=5 where a=1;
select a from t1;
drop table t1;
diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test
index 5c06ef89676..5f21d2b5813 100644
--- a/mysql-test/t/bigint.test
+++ b/mysql-test/t/bigint.test
@@ -14,6 +14,9 @@ select +9999999999999999999,-9999999999999999999;
select cast(9223372036854775808 as unsigned)+1;
select 9223372036854775808+1;
select -(0-3),round(-(0-3)), round(9999999999999999999);
+select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
+select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001;
+select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
#
# In 3.23 we have to disable the test of column to bigint as
diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test
index fed87af3adc..3d630311b3a 100644
--- a/mysql-test/t/ctype_cp932.test
+++ b/mysql-test/t/ctype_cp932.test
@@ -398,6 +398,27 @@ DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
+# Test prepared statement with 0x8300 sequence in parameter while
+# running with cp932 client character set.
+RESET MASTER;
+CREATE TABLE t1(f1 blob);
+PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)';
+SET @var1= x'8300';
+# TODO: Note that this doesn't actually test the code which was added for
+# bug#11338 because this syntax for prepared statements causes the PS to
+# be replicated differently than if we executed the PS from C or Java.
+# Using this syntax, variable names are inserted into the binlog instead
+# of values. The real goal of this test is to check the code that was
+# added to Item_param::query_val_str() in order to do hex encoding of
+# PS parameters when the client character set is cp932;
+# Bug#11338 has an example java program which can be used to verify this
+# code (and I have used it to test the fix) until there is some way to
+# exercise this code from mysql-test-run.
+EXECUTE stmt1 USING @var1;
+SHOW BINLOG EVENTS FROM 98;
+SELECT HEX(f1) FROM t1;
+DROP table t1;
+# end test for bug#11338
SET collation_connection='cp932_japanese_ci';
-- source include/ctype_filesort.inc
diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test
index 8d51b4666e7..f52e12849e4 100644
--- a/mysql-test/t/derived.test
+++ b/mysql-test/t/derived.test
@@ -42,7 +42,7 @@ CREATE TABLE t2 (a int not null);
insert into t2 values(1);
select * from (select * from t1 where t1.a=(select a from t2 where t2.a=t1.a)) a;
select * from (select * from t1 where t1.a=(select t2.a from t2 where t2.a=t1.a) union select t1.a, t1.b from t1) a;
-explain select * from (select * from t1,t2 where t1.a=t2.a) t1;
+explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1;
drop table t1, t2;
create table t1(a int not null, t char(8), index(a));
disable_query_log;
@@ -249,4 +249,13 @@ select * from t1 union distinct select * from t2 union all select * from t3;
select * from (select * from t1 union distinct select * from t2 union all select * from t3) X;
drop table t1, t2, t3;
+#
+# Bug #11864 non unique names are allowed in subquery
+#
+create table t1 (a int);
+create table t2 (a int);
+--error 1060
+select * from (select * from t1,t2) foo;
+drop table t1,t2;
+
# End of 4.1 tests
diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test
index 562926d160c..e69de29bb2d 100644
--- a/mysql-test/t/distinct.test
+++ b/mysql-test/t/distinct.test
@@ -1,344 +0,0 @@
-#
-# Bug with distinct and INSERT INTO
-# Bug with group by and not used fields
-#
-
---disable_warnings
-drop table if exists t1,t2,t3;
---enable_warnings
-
-CREATE TABLE t1 (id int,facility char(20));
-CREATE TABLE t2 (facility char(20));
-INSERT INTO t1 VALUES (NULL,NULL);
-INSERT INTO t1 VALUES (-1,'');
-INSERT INTO t1 VALUES (0,'');
-INSERT INTO t1 VALUES (1,'/L');
-INSERT INTO t1 VALUES (2,'A01');
-INSERT INTO t1 VALUES (3,'ANC');
-INSERT INTO t1 VALUES (4,'F01');
-INSERT INTO t1 VALUES (5,'FBX');
-INSERT INTO t1 VALUES (6,'MT');
-INSERT INTO t1 VALUES (7,'P');
-INSERT INTO t1 VALUES (8,'RV');
-INSERT INTO t1 VALUES (9,'SRV');
-INSERT INTO t1 VALUES (10,'VMT');
-INSERT INTO t2 SELECT DISTINCT FACILITY FROM t1;
-
-select id from t1 group by id;
-select * from t1 order by id;
-select id-5,facility from t1 order by "id-5";
-select id,concat(facility) from t1 group by id ;
-select id+0 as a,max(id),concat(facility) as b from t1 group by a order by b desc,a;
-select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp;
-
-SELECT DISTINCT FACILITY FROM t1;
-SELECT FACILITY FROM t2;
-SELECT count(*) from t1,t2 where t1.facility=t2.facility;
-select count(facility) from t1;
-select count(*) from t1;
-select count(*) from t1 where facility IS NULL;
-select count(*) from t1 where facility = NULL;
-select count(*) from t1 where facility IS NOT NULL;
-select count(*) from t1 where id IS NULL;
-select count(*) from t1 where id IS NOT NULL;
-
-drop table t1,t2;
-
-#
-# Problem with distinct without results
-#
-CREATE TABLE t1 (UserId int(11) DEFAULT '0' NOT NULL);
-INSERT INTO t1 VALUES (20);
-INSERT INTO t1 VALUES (27);
-
-SELECT UserId FROM t1 WHERE Userid=22;
-SELECT UserId FROM t1 WHERE UserId=22 group by Userid;
-SELECT DISTINCT UserId FROM t1 WHERE UserId=22 group by Userid;
-SELECT DISTINCT UserId FROM t1 WHERE UserId=22;
-drop table t1;
-
-#
-# Test of distinct
-#
-
-CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned);
-INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1);
-CREATE TABLE t2 (a int(10) unsigned not null, key (A));
-INSERT INTO t2 VALUES (1),(2);
-CREATE TABLE t3 (a int(10) unsigned, key(A), b text);
-INSERT INTO t3 VALUES (1,'1'),(2,'2');
-SELECT DISTINCT t3.b FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
-INSERT INTO t2 values (1),(2),(3);
-INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2');
-explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
-SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
-
-# Create a lot of data into t3;
-create temporary table t4 select * from t3;
-insert into t3 select * from t4;
-insert into t4 select * from t3;
-insert into t3 select * from t4;
-insert into t4 select * from t3;
-insert into t3 select * from t4;
-insert into t4 select * from t3;
-insert into t3 select * from t4;
-
-explain select distinct t1.a from t1,t3 where t1.a=t3.a;
-#flush status;
-select distinct t1.a from t1,t3 where t1.a=t3.a;
-#show status like 'Handler%';
-#flush status;
-select distinct 1 from t1,t3 where t1.a=t3.a;
-#show status like 'Handler%';
-
-explain SELECT distinct t1.a from t1;
-explain SELECT distinct t1.a from t1 order by a desc;
-explain SELECT t1.a from t1 group by a order by a desc;
-explain SELECT distinct t1.a from t1 order by a desc limit 1;
-explain SELECT distinct a from t3 order by a desc limit 2;
-explain SELECT distinct a,b from t3 order by a+1;
-explain SELECT distinct a,b from t3 order by a limit 10;
-explain SELECT a,b from t3 group by a,b order by a+1;
-
-drop table t1,t2,t3,t4;
-
-CREATE TABLE t1 (name varchar(255));
-INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae');
-SELECT DISTINCT * FROM t1 LIMIT 2;
-SELECT DISTINCT name FROM t1 LIMIT 2;
-SELECT DISTINCT 1 FROM t1 LIMIT 2;
-drop table t1;
-
-CREATE TABLE t1 (
- ID int(11) NOT NULL auto_increment,
- NAME varchar(75) DEFAULT '' NOT NULL,
- LINK_ID int(11) DEFAULT '0' NOT NULL,
- PRIMARY KEY (ID),
- KEY NAME (NAME),
- KEY LINK_ID (LINK_ID)
-);
-
-INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0),(2,'Jack',0),(3,'Bill',0);
-
-CREATE TABLE t2 (
- ID int(11) NOT NULL auto_increment,
- NAME varchar(150) DEFAULT '' NOT NULL,
- PRIMARY KEY (ID),
- KEY NAME (NAME)
-);
-
-SELECT DISTINCT
- t2.id AS key_link_id,
- t2.name AS link
-FROM t1
-LEFT JOIN t2 ON t1.link_id=t2.id
-GROUP BY t1.id
-ORDER BY link;
-drop table t1,t2;
-
-#
-# Problem with table dependencies
-#
-
-create table t1 (
- id int not null,
- name tinytext not null,
- unique (id)
-);
-create table t2 (
- id int not null,
- idx int not null,
- unique (id, idx)
-);
-create table t3 (
- id int not null,
- idx int not null,
- unique (id, idx)
-);
-insert into t1 values (1,'yes'), (2,'no');
-insert into t2 values (1,1);
-insert into t3 values (1,1);
-EXPLAIN
-SELECT DISTINCT
- t1.id
-from
- t1
- straight_join
- t2
- straight_join
- t3
- straight_join
- t1 as j_lj_t2 left join t2 as t2_lj
- on j_lj_t2.id=t2_lj.id
- straight_join
- t1 as j_lj_t3 left join t3 as t3_lj
- on j_lj_t3.id=t3_lj.id
-WHERE
- ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2))
- AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2));
-SELECT DISTINCT
- t1.id
-from
- t1
- straight_join
- t2
- straight_join
- t3
- straight_join
- t1 as j_lj_t2 left join t2 as t2_lj
- on j_lj_t2.id=t2_lj.id
- straight_join
- t1 as j_lj_t3 left join t3 as t3_lj
- on j_lj_t3.id=t3_lj.id
-WHERE
- ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2))
- AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2));
-drop table t1,t2,t3;
-
-#
-# Test using DISTINCT on a function that contains a group function
-# This also test the case when one doesn't use all fields in GROUP BY.
-#
-
-create table t1 (a int not null, b int not null, t time);
-insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15");
-select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b;
-select distinct a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b;
-create table t2 (a int not null primary key, b int);
-insert into t2 values (1,1),(2,2),(3,3);
-select t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b;
-select distinct t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b;
-drop table t1,t2;
-
-#
-# Test problem with DISTINCT and HAVING
-#
-create table t1 (a int not null,b char(5), c text);
-insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4);
-select distinct a from t1 group by b,a having a > 2 order by a desc;
-select distinct a,c from t1 group by b,c,a having a > 2 order by a desc;
-drop table t1;
-
-#
-# Test problem with DISTINCT and ORDER BY DESC
-#
-
-create table t1 (a char(1), key(a)) engine=myisam;
-insert into t1 values('1'),('1');
-select * from t1 where a >= '1';
-select distinct a from t1 order by a desc;
-select distinct a from t1 where a >= '1' order by a desc;
-drop table t1;
-
-#
-# Test when using a not previously used column in ORDER BY
-#
-
-CREATE TABLE t1 (email varchar(50), infoID BIGINT, dateentered DATETIME);
-CREATE TABLE t2 (infoID BIGINT, shipcode varchar(10));
-
-INSERT INTO t1 (email, infoID, dateentered) VALUES
- ('test1@testdomain.com', 1, '2002-07-30 22:56:38'),
- ('test1@testdomain.com', 1, '2002-07-27 22:58:16'),
- ('test2@testdomain.com', 1, '2002-06-19 15:22:19'),
- ('test2@testdomain.com', 2, '2002-06-18 14:23:47'),
- ('test3@testdomain.com', 1, '2002-05-19 22:17:32');
-
-INSERT INTO t2(infoID, shipcode) VALUES
- (1, 'Z001'),
- (2, 'R002');
-
-SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID;
-SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC;
-SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID ORDER BY dateentered DESC;
-drop table t1,t2;
-
-#
-# test with table.* in DISTINCT
-#
-
-CREATE TABLE t1 (privatemessageid int(10) unsigned NOT NULL auto_increment, folderid smallint(6) NOT NULL default '0', userid int(10) unsigned NOT NULL default '0', touserid int(10) unsigned NOT NULL default '0', fromuserid int(10) unsigned NOT NULL default '0', title varchar(250) NOT NULL default '', message mediumtext NOT NULL, dateline int(10) unsigned NOT NULL default '0', showsignature smallint(6) NOT NULL default '0', iconid smallint(5) unsigned NOT NULL default '0', messageread smallint(6) NOT NULL default '0', readtime int(10) unsigned NOT NULL default '0', receipt smallint(6) unsigned NOT NULL default '0', deleteprompt smallint(6) unsigned NOT NULL default '0', multiplerecipients smallint(6) unsigned NOT NULL default '0', PRIMARY KEY (privatemessageid), KEY userid (userid)) ENGINE=MyISAM;
-INSERT INTO t1 VALUES (128,0,33,33,8,':D','',996121863,1,0,2,996122850,2,0,0);
-CREATE TABLE t2 (userid int(10) unsigned NOT NULL auto_increment, usergroupid smallint(5) unsigned NOT NULL default '0', username varchar(50) NOT NULL default '', password varchar(50) NOT NULL default '', email varchar(50) NOT NULL default '', styleid smallint(5) unsigned NOT NULL default '0', parentemail varchar(50) NOT NULL default '', coppauser smallint(6) NOT NULL default '0', homepage varchar(100) NOT NULL default '', icq varchar(20) NOT NULL default '', aim varchar(20) NOT NULL default '', yahoo varchar(20) NOT NULL default '', signature mediumtext NOT NULL, adminemail smallint(6) NOT NULL default '0', showemail smallint(6) NOT NULL default '0', invisible smallint(6) NOT NULL default '0', usertitle varchar(250) NOT NULL default '', customtitle smallint(6) NOT NULL default '0', joindate int(10) unsigned NOT NULL default '0', cookieuser smallint(6) NOT NULL default '0', daysprune smallint(6) NOT NULL default '0', lastvisit int(10) unsigned NOT NULL default '0', lastactivity int(10) unsigned NOT NULL default '0', lastpost int(10) unsigned NOT NULL default '0', posts smallint(5) unsigned NOT NULL default '0', timezoneoffset varchar(4) NOT NULL default '', emailnotification smallint(6) NOT NULL default '0', buddylist mediumtext NOT NULL, ignorelist mediumtext NOT NULL, pmfolders mediumtext NOT NULL, receivepm smallint(6) NOT NULL default '0', emailonpm smallint(6) NOT NULL default '0', pmpopup smallint(6) NOT NULL default '0', avatarid smallint(6) NOT NULL default '0', avatarrevision int(6) unsigned NOT NULL default '0', options smallint(6) NOT NULL default '15', birthday date NOT NULL default '0000-00-00', maxposts smallint(6) NOT NULL default '-1', startofweek smallint(6) NOT NULL default '1', ipaddress varchar(20) NOT NULL default '', referrerid int(10) unsigned NOT NULL default '0', nosessionhash smallint(6) NOT NULL default '0', autorefresh smallint(6) NOT NULL default '-1', messagepopup tinyint(2) NOT NULL default '0', inforum smallint(5) unsigned NOT NULL default '0', ratenum smallint(5) unsigned NOT NULL default '0', ratetotal smallint(5) unsigned NOT NULL default '0', allowrate smallint(5) unsigned NOT NULL default '1', PRIMARY KEY (userid), KEY usergroupid (usergroupid), KEY username (username), KEY inforum (inforum)) ENGINE=MyISAM;
-INSERT INTO t2 VALUES (33,6,'Kevin','0','kevin@stileproject.com',1,'',0,'http://www.stileproject.com','','','','',1,1,0,'Administrator',0,996120694,1,-1,1030996168,1031027028,1030599436,36,'-6',0,'','','',1,0,1,0,0,15,'0000-00-00',-1,1,'64.0.0.0',0,1,-1,0,0,4,19,1);
-SELECT DISTINCT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t2.userid = t1.touserid);
-DROP TABLE t1,t2;
-
-#
-# test with const_item in ORDER BY
-#
-
-CREATE TABLE t1 (a int primary key, b int, c int);
-INSERT t1 VALUES (1,2,3);
-CREATE TABLE t2 (a int primary key, b int, c int);
-INSERT t2 VALUES (3,4,5);
-SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c;
-DROP TABLE t1,t2;
-
-#
-# Test of LEFT() with distinct
-#
-
-CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=3 ;
-INSERT INTO t1 VALUES (1, 'aaaaa');
-INSERT INTO t1 VALUES (3, 'aaaaa');
-INSERT INTO t1 VALUES (2, 'eeeeeee');
-select distinct left(name,1) as name from t1;
-drop table t1;
-
-#
-# Test case from sel000100
-#
-
-CREATE TABLE t1 (
- ID int(11) NOT NULL auto_increment,
- NAME varchar(75) DEFAULT '' NOT NULL,
- LINK_ID int(11) DEFAULT '0' NOT NULL,
- PRIMARY KEY (ID),
- KEY NAME (NAME),
- KEY LINK_ID (LINK_ID)
-);
-
-INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0);
-INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (2,'Jack',0);
-INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (3,'Bill',0);
-
-CREATE TABLE t2 (
- ID int(11) NOT NULL auto_increment,
- NAME varchar(150) DEFAULT '' NOT NULL,
- PRIMARY KEY (ID),
- KEY NAME (NAME)
-);
-
-SELECT DISTINCT
- t2.id AS key_link_id,
- t2.name AS link
-FROM t1
-LEFT JOIN t2 ON t1.link_id=t2.id
-GROUP BY t1.id
-ORDER BY link;
-drop table t1,t2;
-
-#
-# test case for #674
-#
-
-CREATE TABLE t1 (
- html varchar(5) default NULL,
- rin int(11) default '0',
- rout int(11) default '0'
-) ENGINE=MyISAM;
-
-INSERT INTO t1 VALUES ('1',1,0);
-SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
-drop table t1;
-
-#
-# Bug 9784 DISTINCT IFNULL truncates data
-#
-create table t1 (id int, dsc varchar(50));
-insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three");
-select distinct id, IFNULL(dsc, '-') from t1;
-drop table t1;
-
-# End of 4.1 tests
diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test
index 93668ffdd3d..f5647a293e8 100644
--- a/mysql-test/t/errors.test
+++ b/mysql-test/t/errors.test
@@ -14,9 +14,9 @@ update t1 set a=1;
create table t1 (a int);
--error 1054
select count(test.t1.b) from t1;
---error 1109
+--error 1054
select count(not_existing_database.t1) from t1;
---error 1109
+--error 1054
select count(not_existing_database.t1.a) from t1;
--error 1044,1146
select count(not_existing_database.t1.a) from not_existing_database.t1;
@@ -31,3 +31,14 @@ select count(*),b from t1;
drop table t1;
# End of 4.1 tests
+
+#
+# Bug #6080: Error message for a field with a display width that is too long
+#
+--error 1439
+create table t1 (a int(256));
+set sql_mode='traditional';
+--error 1074
+create table t1 (a varchar(66000));
+
+# End of 5.0 tests
diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test
index f2bfa45ba59..f5fd9fcadf2 100644
--- a/mysql-test/t/flush.test
+++ b/mysql-test/t/flush.test
@@ -70,4 +70,35 @@ insert into t1 values (345);
select * from t1;
drop table t1;
+#
+# Bug#9459 - deadlock with flush with lock, and lock table write
+#
+create table t1 (c1 int);
+lock table t1 write;
+# Cannot get the global read lock with write locked tables.
+--error 1192
+flush tables with read lock;
+lock table t1 read;
+# Can get the global read lock with read locked tables.
+flush tables with read lock;
+--error 1223
+lock table t1 write;
+lock table t1 read;
+--error 1223
+lock table t1 write;
+# Release all table locks and the global read lock.
+unlock tables;
+create table t2 (c1 int);
+create table t3 (c1 int);
+lock table t1 read, t2 read, t3 write;
+# Cannot get the global read lock with write locked tables.
+--error 1192
+flush tables with read lock;
+lock table t1 read, t2 read, t3 read;
+# Can get the global read lock with read locked tables.
+flush tables with read lock;
+# Release all table locks and the global read lock.
+unlock tables;
+drop table t1, t2, t3;
+
# End of 4.1 tests
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 300bea1c917..08648f4e0a6 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -128,14 +128,14 @@ WHERE ticket2.id = ttxt.ticket AND t1.id = ticket2.ticket and
match(ttxt.inhalt) against ('foobar');
# In the following query MySQL didn't use the fulltext index
-select t1.id FROM t2 as ttxt,t1 INNER JOIN t1 as ticket2 ON
-ticket2.id = ttxt.ticket
-WHERE t1.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar');
+select ticket2.id FROM t2 as ttxt,t2 INNER JOIN t1 as ticket2 ON
+ticket2.id = t2.ticket
+WHERE ticket2.id = ticket2.ticket and match(ttxt.inhalt) against ('foobar');
INSERT INTO t1 VALUES (3,3);
-select t1.id FROM t2 as ttxt,t1
-INNER JOIN t1 as ticket2 ON ticket2.id = ttxt.ticket
-WHERE t1.id = ticket2.ticket and
+select ticket2.id FROM t2 as ttxt,t2
+INNER JOIN t1 as ticket2 ON ticket2.id = t2.ticket
+WHERE ticket2.id = ticket2.ticket and
match(ttxt.inhalt) against ('foobar');
# Check that we get 'fulltext' index in SHOW CREATE
diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test
index a0bd7954674..074aefbf943 100644
--- a/mysql-test/t/fulltext_order_by.test
+++ b/mysql-test/t/fulltext_order_by.test
@@ -1,5 +1,5 @@
--disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1,t2,t3;
--enable_warnings
CREATE TABLE t1 (
@@ -80,7 +80,7 @@ CREATE TABLE t3 (
FULLTEXT KEY betreff (betreff)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ;
---error 1109
+--error 1054
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@@ -100,7 +100,7 @@ group by
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
---error 1109
+--error 1054
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@@ -117,8 +117,6 @@ where
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
--- todo psergey: fix
---error 1214
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@@ -135,6 +133,22 @@ where
order by
match(betreff) against ('+abc' in boolean mode) desc;
+# BUG#11869 part2: used table type doesn't support FULLTEXT indexes error
+(select b.id, b.betreff from t3 b) union
+(select b.id, b.betreff from t3 b)
+order by match(betreff) against ('+abc' in boolean mode) desc;
+
+--error 1191
+(select b.id, b.betreff from t3 b) union
+(select b.id, b.betreff from t3 b)
+order by match(betreff) against ('+abc') desc;
+
+select distinct b.id, b.betreff from t3 b
+order by match(betreff) against ('+abc' in boolean mode) desc;
+
+select b.id, b.betreff from t3 b group by b.id+1
+order by match(betreff) against ('+abc' in boolean mode) desc;
+
drop table t1,t2,t3;
# End of 4.1 tests
diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test
index b768e4fec61..e01fce30577 100644
--- a/mysql-test/t/func_date_add.test
+++ b/mysql-test/t/func_date_add.test
@@ -41,4 +41,27 @@ select visitor_id,max(ts) as mts from t1 group by visitor_id
having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW();
drop table t1;
+#
+# Bug #10627: Invalid date turned to NULL from date_sub/date_add in
+# traditional mode
+#
+set sql_mode='traditional';
+create table t1 (d date);
+--error S22008
+insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR);
+--error S22008
+insert into t1 (d) select date_add('2000-01-01',interval 8000 year);
+# No warnings/errors from the next two
+insert into t1 values (date_add(NULL, INTERVAL 1 DAY));
+insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY));
+set sql_mode='';
+# These will all work now, and we'll end up with some NULL entries in the
+# table and some warnings.
+insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR);
+insert into t1 (d) select date_add('2000-01-01',interval 8000 year);
+insert into t1 values (date_add(NULL, INTERVAL 1 DAY));
+insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY));
+select * from t1;
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index 5079e2605ce..4a618a56483 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -46,3 +46,35 @@ drop table t1;
create table t1 as select uuid(), length(uuid());
show create table t1;
drop table t1;
+
+# Bug #6760: Add SLEEP() function
+create table t1 (a timestamp default '2005-05-05 01:01:01',
+ b timestamp default '2005-05-05 01:01:01');
+insert into t1 set a = now();
+select sleep(3);
+update t1 set b = now();
+select timediff(b, a) >= '00:00:03' from t1;
+drop table t1;
+
+#
+# Bug #12689: SLEEP() gets incorrectly cached/optimized-away
+#
+set global query_cache_size=1355776;
+create table t1 (a int);
+insert into t1 values (1),(1),(1);
+create table t2 (a datetime default null, b datetime default null);
+insert into t2 set a = now();
+select a from t1 where sleep(1);
+update t2 set b = now() where b is null;
+insert into t2 set a = now();
+select a from t1 where sleep(a);
+update t2 set b = now() where b is null;
+insert into t2 set a = now();
+select a from t1 where sleep(1);
+update t2 set b = now() where b is null;
+select timediff(b, a) >= '00:00:03' from t2;
+drop table t2;
+drop table t1;
+set global query_cache_size=default;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index c66f3eaa294..4a6c98c8d7f 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -23,6 +23,45 @@ select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',s
select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1);
select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1);
select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1);
+select substring_index('aaaaaaaaa1','a',1);
+select substring_index('aaaaaaaaa1','aa',1);
+select substring_index('aaaaaaaaa1','aa',2);
+select substring_index('aaaaaaaaa1','aa',3);
+select substring_index('aaaaaaaaa1','aa',4);
+select substring_index('aaaaaaaaa1','aa',5);
+select substring_index('aaaaaaaaa1','aaa',1);
+select substring_index('aaaaaaaaa1','aaa',2);
+select substring_index('aaaaaaaaa1','aaa',3);
+select substring_index('aaaaaaaaa1','aaa',4);
+select substring_index('aaaaaaaaa1','aaaa',1);
+select substring_index('aaaaaaaaa1','aaaa',2);
+select substring_index('aaaaaaaaa1','1',1);
+select substring_index('aaaaaaaaa1','a',-1);
+select substring_index('aaaaaaaaa1','aa',-1);
+select substring_index('aaaaaaaaa1','aa',-2);
+select substring_index('aaaaaaaaa1','aa',-3);
+select substring_index('aaaaaaaaa1','aa',-4);
+select substring_index('aaaaaaaaa1','aa',-5);
+select substring_index('aaaaaaaaa1','aaa',-1);
+select substring_index('aaaaaaaaa1','aaa',-2);
+select substring_index('aaaaaaaaa1','aaa',-3);
+select substring_index('aaaaaaaaa1','aaa',-4);
+select substring_index('the king of thethe hill','the',-2);
+select substring_index('the king of the the hill','the',-2);
+select substring_index('the king of the the hill','the',-2);
+select substring_index('the king of the the hill',' the ',-1);
+select substring_index('the king of the the hill',' the ',-2);
+select substring_index('the king of the the hill',' ',-1);
+select substring_index('the king of the the hill',' ',-2);
+select substring_index('the king of the the hill',' ',-3);
+select substring_index('the king of the the hill',' ',-4);
+select substring_index('the king of the the hill',' ',-5);
+select substring_index('the king of the.the hill','the',-2);
+select substring_index('the king of thethethe.the hill','the',-3);
+select substring_index('the king of thethethe.the hill','the',-1);
+select substring_index('the king of the the hill','the',1);
+select substring_index('the king of the the hill','the',2);
+select substring_index('the king of the the hill','the',3);
select concat(':',ltrim(' left '),':',rtrim(' right '),':');
select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':');
diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test
index d7e215f5d48..4a526935491 100644
--- a/mysql-test/t/func_system.test
+++ b/mysql-test/t/func_system.test
@@ -32,6 +32,18 @@ drop table t1;
select TRUE,FALSE,NULL;
#
+# Bug#12351: CONCAT with USER()/DATEBASE() and
+# a constant and a column gets strange results
+#
+create table t1 (c1 char(5)) character set=latin1;
+insert into t1 values('row 1');
+insert into t1 values('row 2');
+insert into t1 values('row 3');
+select concat(user(), '--', c1) from t1;
+select concat(database(), '--', c1) from t1;
+drop table t1;
+
+#
# Bug#8291 Illegal collation mix with USER() function
#
create table t1 (a char(10)) character set latin1;
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 0538e6111b9..3dd7f7276fb 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -353,3 +353,55 @@ select last_day('2005-01-00');
# the 0-11 range
#
select time_format('100:00:00', '%H %k %h %I %l');
+
+#
+# Bug #12562: Make SYSDATE behave like it does in Oracle: always the current
+# time, regardless of magic to make NOW() always the same for the
+# entirety of a statement.
+create table t1 (a timestamp default '2005-05-05 01:01:01',
+ b timestamp default '2005-05-05 01:01:01');
+delimiter //;
+create function t_slow_sysdate() returns timestamp
+begin
+ do sleep(2);
+ return sysdate();
+end;
+//
+
+insert into t1 set a = sysdate(), b = t_slow_sysdate();//
+
+create trigger t_before before insert on t1
+for each row begin
+ set new.b = t_slow_sysdate();
+end
+//
+
+delimiter ;//
+
+insert into t1 set a = sysdate();
+
+select a != b from t1;
+
+drop trigger t_before;
+drop function t_slow_sysdate;
+drop table t1;
+
+create table t1 (a datetime, i int, b datetime);
+insert into t1 select sysdate(), sleep(1), sysdate() from dual;
+select a != b from t1;
+drop table t1;
+
+delimiter //;
+create procedure t_sysdate()
+begin
+ select sysdate() into @a;
+ do sleep(2);
+ select sysdate() into @b;
+ select @a != @b;
+end;
+//
+delimiter ;//
+call t_sysdate();
+drop procedure t_sysdate;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 05094b29589..635c7a3f4e7 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -480,4 +480,11 @@ flush privileges;
delete from tables_priv where host = '' and user = 'mysqltest_1';
flush privileges;
+#
+# Bug #10892 user variables not auto cast for comparisons
+# Check that we don't get illegal mix of collations
+#
+set @user123="non-existent";
+select * from mysql.db where user=@user123;
+
# End of 4.1 tests
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index c6b8bfe2916..ee9cd1924c6 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -310,7 +310,45 @@ select * from t1;
disconnect n1;
connection default;
REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
drop table mysqltest_1.t1;
+
+#
+# Bug #12302: 'SET PASSWORD = ...' didn't work if connecting hostname !=
+# hostname the current user is authenticated as. Note that a test for this
+# was also added to the test above.
+#
+grant all on mysqltest_1.* to mysqltest_1@'127.0.0.1';
+connect (b12302,127.0.0.1,mysqltest_1,,mysqltest_1,$MASTER_MYPORT,);
+connection b12302;
+select current_user();
+set password = password('changed');
+disconnect b12302;
+connection default;
+select host, length(password) from mysql.user where user like 'mysqltest\_1';
+revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.1';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
+grant all on mysqltest_1.* to mysqltest_1@'127.0.0.0/255.0.0.0';
+connect (b12302_2,127.0.0.1,mysqltest_1,,mysqltest_1,$MASTER_MYPORT,);
+connection b12302_2;
+select current_user();
+set password = password('changed');
+disconnect b12302_2;
+connection default;
+select host, length(password) from mysql.user where user like 'mysqltest\_1';
+revoke all on mysqltest_1.* from mysqltest_1@'127.0.0.0/255.0.0.0';
+delete from mysql.user where user like 'mysqltest\_1';
+flush privileges;
drop database mysqltest_1;
+# But anonymous users can't change their password
+connect (n5,localhost,test,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection n5;
+--error 1044
+set password = password("changed");
+disconnect n5;
+connection default;
+
# End of 4.1 tests
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index bfbdd098426..8300b502518 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -575,12 +575,22 @@ CREATE TABLE t1 (id varchar(20) NOT NULL);
INSERT INTO t1 VALUES ('trans1'), ('trans2');
CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL);
INSERT INTO t2 VALUES ('trans1', 'a problem');
-
SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment
FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment;
DROP TABLE t1, t2;
+
+#
+# Bug #12266 GROUP BY expression on DATE column produces result with
+# reduced length
+#
+create table t1 (f1 date);
+insert into t1 values('2005-06-06');
+insert into t1 values('2005-06-06');
+select date(left(f1+0,8)) from t1 group by 1;
+drop table t1;
+
#
# Test for bug #11414: crash on Windows for a simple GROUP BY query
#
diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test
index 6a9ff5c8284..fcaa4c41ece 100644
--- a/mysql-test/t/heap.test
+++ b/mysql-test/t/heap.test
@@ -437,3 +437,14 @@ insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd
drop table t1;
# End of 4.1 tests
+
+#
+# Bug #3094: Row format of memory tables should always be reported as Fixed
+#
+create table t1 (c char(10)) engine=memory;
+create table t2 (c varchar(10)) engine=memory;
+--replace_column 8 #
+show table status like 't_';
+drop table t1, t2;
+
+# End of 5.0 tests
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index cf089f0089e..23f88b75576 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -5,7 +5,7 @@
# show databases
--disable_warnings
-DROP TABLE IF EXISTS t0,t1,t2;
+DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
--enable_warnings
@@ -30,6 +30,8 @@ create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
create table test.t2(a int);
create table t3(a int, KEY a_data (a));
create table mysqltest.t4(a int);
+create table t5 (id int auto_increment primary key);
+insert into t5 values (10);
create view v1 (c) as select table_name from information_schema.TABLES;
select * from v1;
@@ -76,7 +78,7 @@ where table_schema = 'mysqltest' and table_name = 'v1';
connection default;
drop view v1, mysqltest.v1;
-drop tables mysqltest.t4, mysqltest.t1, t2, t3;
+drop tables mysqltest.t4, mysqltest.t1, t2, t3, t5;
drop database mysqltest;
# Test for information_schema.CHARACTER_SETS &
@@ -136,7 +138,7 @@ information_schema.SCHEMATA b where
a.ROUTINE_SCHEMA = b.SCHEMA_NAME;
select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
-mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
+mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8) order by 1;
select count(*) from information_schema.ROUTINES;
connect (user1,localhost,mysqltest_1,,);
@@ -613,6 +615,7 @@ show create database information_schema;
#
# Bug #11057 information_schema: columns table has some questionable contents
+# Bug #12301 information_schema: NUMERIC_SCALE must be 0 for integer columns
#
create table t1(f1 LONGBLOB, f2 LONGTEXT);
select column_name,data_type,CHARACTER_OCTET_LENGTH,
@@ -637,3 +640,29 @@ select trigger_schema, trigger_name from triggers where
trigger_name='tr1';
use test;
drop table t1;
+
+#
+# Bug#12518 COLUMN_DEFAULT has wrong value if NOT NULL is set
+#
+create table t1 (a int not null, b int);
+use information_schema;
+select column_name, column_default from columns
+ where table_schema='test' and table_name='t1';
+use test;
+show columns from t1;
+drop table t1;
+
+#
+# Bug #12636: SHOW TABLE STATUS with where condition containing a subquery
+# over information schema
+#
+
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (b int);
+
+--replace_column 8 # 12 # 13 #
+SHOW TABLE STATUS FROM test
+ WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE');
+
+DROP TABLE t1,t2
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 05f47f36e42..bf094dd0e5d 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -441,6 +441,7 @@ set @a:=now();
CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb;
insert into t1 (a) values(1),(2),(3);
select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a;
+select a from t1 natural join t1 as t2 where b >= @a order by a;
update t1 set a=5 where a=1;
select a from t1;
drop table t1;
@@ -586,7 +587,7 @@ insert into mysqltest.t3 values(1);
commit;
drop database mysqltest;
# Don't check error message
---error 12,12
+--error 1049
show tables from mysqltest;
#
@@ -981,7 +982,7 @@ insert into `t3`values ( 1 ) ;
delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
--error 1217
update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
---error 1109
+--error 1054
update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
drop table t3,t2,t1;
@@ -1394,3 +1395,13 @@ SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300;
SELECT GRADE FROM t1 WHERE GRADE= 151;
DROP TABLE t1;
+#
+# Bug #12340 multitable delete deletes only one record
+#
+create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb;
+create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb;
+insert into t2 values ('aa','cc');
+insert into t1 values ('aa','bb'),('aa','cc');
+delete t1 from t1,t2 where f1=f3 and f4='cc';
+select * from t1;
+drop table t1,t2;
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 4a463c1d52e..7116a25ff39 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -196,9 +196,9 @@ insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a +
#Some error cases
--error 1052
insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
---error 1109
+--error 1054
insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b;
---error 1109
+--error 1054
insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b;
drop table t1,t2,t3;
diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test
index 5948f92d4e0..eda768be1bc 100644
--- a/mysql-test/t/insert_update.test
+++ b/mysql-test/t/insert_update.test
@@ -101,4 +101,18 @@ insert into t1 select a from t1 on duplicate key update a=a+1 ;
insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ;
drop table t1;
+#
+# Bug#10109 - INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails
+# Bogus "Duplicate columns" error message
+#
+
+CREATE TABLE t1 (
+ a BIGINT(20) NOT NULL DEFAULT 0,
+ PRIMARY KEY (a)
+) ENGINE=MyISAM;
+
+INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ;
+
+DROP TABLE t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test
index 2715f30b6cf..bb82a93c6c4 100644
--- a/mysql-test/t/join.test
+++ b/mysql-test/t/join.test
@@ -115,6 +115,10 @@ select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using
--replace_result "31 tables" "XX tables" "61 tables" "XX tables"
--error 1116
select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
+select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a);
+--replace_result "31 tables" "XX tables" "61 tables" "XX tables"
+--error 1116
+select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a);
drop table t1;
#
@@ -145,6 +149,7 @@ CREATE TABLE t1 (d DATE NOT NULL);
CREATE TABLE t2 (d DATE NOT NULL);
INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00');
SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL;
+SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL;
SELECT * from t1 WHERE t1.d IS NULL;
SELECT * FROM t1 WHERE 1/0 IS NULL;
DROP TABLE t1,t2;
@@ -268,6 +273,8 @@ CREATE TABLE t2 (
INSERT INTO t2 VALUES ('rivercats','cust',20);
SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats';
SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith';
+SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats';
+SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith';
drop table t1,t2;
#
diff --git a/mysql-test/t/join_crash.test b/mysql-test/t/join_crash.test
index 68fd9226e41..2ec96dc2c28 100644
--- a/mysql-test/t/join_crash.test
+++ b/mysql-test/t/join_crash.test
@@ -92,18 +92,11 @@ select distinct
t1.comments as comments,
sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget
from
- t1 ,
t2 as client_period ,
- t2 as project_period
- left join
- t3
- on
- t3.project_ptr = t1.project_id
- and t3.date_received <= '2001-03-22 14:15:09'
- left join
- t4
- on
- t4.client_id = t1.client_ptr
+ t2 as project_period,
+ t3 left join t1 on (t3.project_ptr = t1.project_id and
+ t3.date_received <= '2001-03-22 14:15:09')
+ left join t4 on t4.client_id = t1.client_ptr
where
1
and ( client_period.period_type = 'client_table'
diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test
index 992217d0391..482c7f9f8b9 100644
--- a/mysql-test/t/join_nested.test
+++ b/mysql-test/t/join_nested.test
@@ -130,15 +130,13 @@ SELECT t8.a,t8.b
EXPLAIN EXTENDED
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
- FROM t6,
- t7
+ FROM (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10;
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
- FROM t6,
- t7
+ FROM (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10;
@@ -150,8 +148,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
FROM t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -162,8 +159,7 @@ SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
FROM t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -186,8 +182,7 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -203,8 +198,7 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -228,8 +222,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -252,8 +245,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -281,8 +273,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -308,8 +299,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -336,8 +326,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -375,8 +364,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -452,7 +440,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
WHERE t1.a <= 2;
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
- FROM t1, t3, t4
+ FROM t1, (t3, t4)
RIGHT JOIN
t2
ON t3.a=1 AND t2.b=t4.b
@@ -460,7 +448,7 @@ SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
EXPLAIN EXTENDED
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
- FROM t1, t3, t4
+ FROM t1, (t3, t4)
RIGHT JOIN
t2
ON t3.a=1 AND t2.b=t4.b
@@ -470,13 +458,13 @@ CREATE INDEX idx_b ON t2(b);
EXPLAIN EXTENDED
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
- FROM t3,t4
+ FROM (t3,t4)
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
- FROM t3,t4
+ FROM (t3,t4)
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
@@ -494,8 +482,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -534,8 +521,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -573,8 +559,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -613,8 +598,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -649,8 +633,7 @@ SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
t5
LEFT JOIN
(
- t6,
- t7
+ (t6, t7)
LEFT JOIN
t8
ON t7.b=t8.b AND t6.b < 10
@@ -770,3 +753,51 @@ SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21;
EXPLAIN SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21;
DROP TABLE t1,t2,t3;
+
+#
+# Bug #12154: creation of temp table for a query with nested outer join
+#
+
+CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL);
+INSERT INTO t1 VALUES (23, 2340), (26, 9900);
+
+CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2));
+INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr');
+
+create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL);
+INSERT INTO t3 VALUES (3,23), (6,26);
+
+CREATE TABLE t4 (groupid int(12));
+INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6);
+
+SELECT * FROM
+(SELECT DISTINCT gl.groupid, gp.price
+ FROM t4 gl
+ LEFT JOIN
+ (t3 g INNER JOIN t2 p ON g.goodsid = p.goods
+ INNER JOIN t1 gp ON p.goods = gp.goods)
+ ON gl.groupid = g.groupid and p.shop = 'fr') t;
+
+CREATE VIEW v1 AS
+SELECT g.groupid groupid, p.goods goods,
+ p.name name, p.shop shop,
+ gp.price price
+ FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods
+ INNER JOIN t1 gp on p.goods = gp.goods;
+
+CREATE VIEW v2 AS
+SELECT DISTINCT g.groupid, fr.price
+ FROM t4 g
+ LEFT JOIN
+ v1 fr on g.groupid = fr.groupid and fr.shop = 'fr';
+
+SELECT * FROM v2;
+
+SELECT * FROM
+(SELECT DISTINCT g.groupid, fr.price
+ FROM t4 g
+ LEFT JOIN
+ v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t;
+
+DROP VIEW v1,v2;
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test
index f48ae985e56..aabc32c009a 100644
--- a/mysql-test/t/join_outer.test
+++ b/mysql-test/t/join_outer.test
@@ -34,13 +34,13 @@ explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a);
# The next query should rearange the left joins to get this to work
---error 1120
+--error 1054
explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
---error 1120
+--error 1054
select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a);
# The next query should give an error in MySQL
---error 1120
+--error 1054
select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a);
# Test of inner join
@@ -292,7 +292,7 @@ insert into t3 values (1);
insert into t4 values (1,1);
insert into t5 values (1,1);
---error 1120
+--error 1054
explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23;
drop table t1,t2,t3,t4,t5;
@@ -432,6 +432,8 @@ insert into t3 values(2),(4);
select * from t1 natural left join t2 natural left join t3;
select * from t1 natural left join t2 where (t2.i is not null)=0;
select * from t1 natural left join t2 where (t2.i is not null) is not null;
+select * from t1 natural left join t2 where (i is not null)=0;
+select * from t1 natural left join t2 where (i is not null) is not null;
drop table t1,t2,t3;
#
@@ -440,7 +442,6 @@ drop table t1,t2,t3;
create table t1 (f1 integer,f2 integer,f3 integer);
create table t2 (f2 integer,f4 integer);
create table t3 (f3 integer,f5 integer);
---error 1054
select * from t1
left outer join t2 using (f2)
left outer join t3 using (f3);
@@ -659,6 +660,8 @@ insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb");
insert into t2 values (1,"cccccccccc"),(2,"dddddddddd");
select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a;
select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a;
+select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a;
+select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a;
drop table t1, t2;
set group_concat_max_len=default;
diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test
index 5d0f904a716..df584021af1 100644
--- a/mysql-test/t/key_cache.test
+++ b/mysql-test/t/key_cache.test
@@ -168,4 +168,11 @@ check table t1;
drop table t1;
+#
+# Bug#10473 - Can't set 'key_buffer_size' system variable to ZERO
+# (One cannot drop the default key cache.)
+#
+set @@global.key_buffer_size=0;
+select @@global.key_buffer_size;
+
# End of 4.1 tests
diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test
index 09ad3f59c10..3503d5fde1d 100644
--- a/mysql-test/t/kill.test
+++ b/mysql-test/t/kill.test
@@ -15,6 +15,7 @@ connection con1;
drop table if exists t1;
--enable_warnings
+--disable_reconnect
create table t1 (kill_id int);
insert into t1 values(connection_id());
@@ -25,7 +26,6 @@ kill @id;
connection con1;
---disable_reconnect
# this statement should fail
--error 2006,2013
select 1;
diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test
index b4edd15f5ef..65338448555 100644
--- a/mysql-test/t/metadata.test
+++ b/mysql-test/t/metadata.test
@@ -49,4 +49,16 @@ drop table t1;
--disable_metadata
+#
+# Bug #11688: Bad mysql_info() results in multi-results
+#
+--enable_info
+delimiter //;
+create table t1 (i int);
+insert into t1 values (1),(2),(3);
+select * from t1 where i = 2;
+drop table t1;//
+delimiter ;//
+--disable_info
+
# End of 4.1 tests
diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test
index bfc278d709b..0f7b0bb7edc 100644
--- a/mysql-test/t/ndb_alter_table.test
+++ b/mysql-test/t/ndb_alter_table.test
@@ -151,7 +151,6 @@ select * from t1 where b = 'two';
connection server1;
alter table t1 drop index c;
connection server2;
---error 1412
select * from t1 where b = 'two';
select * from t1 where b = 'two';
connection server1;
@@ -180,4 +179,29 @@ drop table t1;
#select count(*) from t2;
#drop table t2;
+connection server1;
+create table t3 (a int primary key) engine=ndbcluster;
+
+connection server2;
+begin;
+insert into t3 values (1);
+
+connection server1;
+alter table t3 rename t4;
+
+connection server2;
+# This should work as transaction is ongoing...
+delete from t3;
+insert into t3 values (1);
+commit;
+
+# This should fail as its a new transaction
+--error 1015
+select * from t3;
+select * from t4;
+drop table t4;
+show tables;
+connection server1;
+
# End of 4.1 tests
+
diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test
index 66287bf6d29..ab3063af672 100644
--- a/mysql-test/t/ndb_config.test
+++ b/mysql-test/t/ndb_config.test
@@ -1,4 +1,5 @@
-- source include/have_ndb.inc
+-- source include/ndb_default_cluster.inc
-- source include/not_embedded.inc
--exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host 2> /dev/null
diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test
index e3b26a3e47f..b1807579b20 100644
--- a/mysql-test/t/order_by.test
+++ b/mysql-test/t/order_by.test
@@ -158,10 +158,21 @@ LEFT JOIN t3 ON t3.c = t1.c;
SELECT a,b,if(b = 1,i,if(b = 2,v,''))
FROM t1
+LEFT JOIN t2 ON t1.c = t2.c
+LEFT JOIN t3 ON t3.c = t1.c;
+
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
LEFT JOIN t2 USING(c)
LEFT JOIN t3 ON t3.c = t1.c
ORDER BY a;
+SELECT a,b,if(b = 1,i,if(b = 2,v,''))
+FROM t1
+LEFT JOIN t2 ON t1.c = t2.c
+LEFT JOIN t3 ON t3.c = t1.c
+ORDER BY a;
+
drop table t1,t2,t3;
#
@@ -340,7 +351,9 @@ CREATE TABLE t2 (
INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug');
INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug');
SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
+SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
+SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30;
drop table t1,t2;
#
diff --git a/mysql-test/t/query_cache_notembedded.test b/mysql-test/t/query_cache_notembedded.test
index d29dc10ccae..fd4785ffe95 100644
--- a/mysql-test/t/query_cache_notembedded.test
+++ b/mysql-test/t/query_cache_notembedded.test
@@ -78,4 +78,23 @@ show status like "Qcache_total_blocks";
show status like "Qcache_free_blocks";
drop table t1, t2, t3, t11, t21;
+#
+# do not use QC if tables locked (BUG#12385)
+#
+connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connection root;
+CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE =
+MyISAM;
+LOCK TABLE t1 READ LOCAL;
+connect (root2,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connection root2;
+INSERT INTO t1 VALUES (), (), ();
+connection root;
+SELECT * FROM t1;
+connection root2;
+SELECT * FROM t1;
+connection root;
+SELECT * FROM t1;
+drop table t1;
+
set GLOBAL query_cache_size=0;
diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test
index 4becef1c2b7..6301cc0f584 100644
--- a/mysql-test/t/row.test
+++ b/mysql-test/t/row.test
@@ -86,3 +86,9 @@ SELECT ROW(2,10) <=> ROW(3,4);
SELECT ROW(NULL,10) <=> ROW(3,NULL);
# End of 4.1 tests
+
+#
+# Correct NULL handling in row comporison (BUG#12509)
+#
+SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ;
+select row(NULL,1)=(2,0);
diff --git a/mysql-test/t/rpl_delete_all.test b/mysql-test/t/rpl_delete_all.test
index db33ee3bb86..e0c0757bbc2 100644
--- a/mysql-test/t/rpl_delete_all.test
+++ b/mysql-test/t/rpl_delete_all.test
@@ -7,7 +7,7 @@ drop database if exists mysqltest;
sync_slave_with_master;
# can't read dir
--replace_result "Errcode: 1" "Errcode: X" "Errcode: 2" "Errcode: X" \\ /
---error 12
+--error 1049
show tables from mysqltest;
connection slave;
diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test
new file mode 100644
index 00000000000..7b4a56910d6
--- /dev/null
+++ b/mysql-test/t/rpl_drop_db.test
@@ -0,0 +1,56 @@
+# test case for BUG#4680 -- if there are extra files in the db directory
+# dropping the db on the master causes replication problems
+
+-- source include/master-slave.inc
+connection master;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+create table mysqltest.t1 (n int);
+insert into mysqltest.t1 values (1);
+select * from mysqltest.t1 into outfile 'mysqltest/f1.txt';
+create table mysqltest.t2 (n int);
+create table mysqltest.t3 (n int);
+--error 1010
+drop database mysqltest;
+use mysqltest;
+show tables;
+
+# test the branch of the code that deals with the query buffer overflow
+
+disable_query_log;
+let $1=50;
+while ($1)
+{
+ eval create table mysqltest.mysql_test_long_table_name$1 (n int);
+ dec $1;
+}
+enable_query_log;
+--error 1010
+drop database mysqltest;
+use mysqltest;
+show tables;
+use test;
+create table t1 (n int);
+insert into t1 values (1234);
+sync_slave_with_master;
+
+connection slave;
+use mysqltest;
+show tables;
+use test;
+select * from t1;
+
+connection master;
+drop table t1;
+sync_slave_with_master;
+
+#cleanup
+connection slave;
+stop slave;
+system rm -rf var/master-data/mysqltest;
+
+# End of 4.1 tests
+
diff --git a/mysql-test/t/rpl_insert_select.test b/mysql-test/t/rpl_insert_select.test
new file mode 100644
index 00000000000..677be526982
--- /dev/null
+++ b/mysql-test/t/rpl_insert_select.test
@@ -0,0 +1,19 @@
+# Testcase for BUG#10456 - INSERT INTO ... SELECT violating a primary key
+# breaks replication
+
+-- source include/master-slave.inc
+connection master;
+
+create table t1 (n int not null primary key);
+insert into t1 values (1);
+create table t2 (n int);
+insert into t2 values (1);
+insert ignore into t1 select * from t2;
+insert into t1 values (2);
+sync_slave_with_master;
+connection slave;
+select * from t1;
+
+connection master;
+drop table t1,t2;
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test
index 78731e4dc7d..3c151721d8e 100644
--- a/mysql-test/t/rpl_openssl.test
+++ b/mysql-test/t/rpl_openssl.test
@@ -7,7 +7,7 @@ source include/master-slave.inc;
# creating replication user for whom ssl auth is required
# preparing playground
connection master;
-grant replication slave on *.* to replssl@'%' require ssl;
+grant replication slave on *.* to replssl@localhost require ssl;
create table t1 (t int);
save_master_pos;
diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test
new file mode 100644
index 00000000000..715222f0314
--- /dev/null
+++ b/mysql-test/t/rpl_trigger.test
@@ -0,0 +1,118 @@
+#
+# Test of triggers with replication
+#
+
+source include/master-slave.inc;
+
+#
+# #12482: Triggers has side effects with auto_increment values
+#
+
+create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null);
+create table t2 (a int auto_increment, primary key (a), b int);
+create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null);
+
+delimiter |;
+create trigger t1 before insert on t1 for each row
+begin
+ insert into t3 values (NULL, "t1", new.a, new.b, rand());
+end|
+
+create trigger t2 after insert on t2 for each row
+begin
+ insert into t3 values (NULL, "t2", new.a, new.b, rand());
+end|
+delimiter ;|
+
+insert into t3 values(100,"log",0,0,0);
+
+# Ensure we always have same random numbers
+SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
+
+# Emulate that we have rows 2-9 deleted on the slave
+insert into t1 values(1,1,rand()),(NULL,2,rand());
+insert into t2 (b) values(last_insert_id());
+insert into t2 values(3,0),(NULL,0);
+insert into t2 values(NULL,0),(500,0);
+
+select a,b, truncate(rand_value,4) from t1;
+select * from t2;
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+save_master_pos;
+connection slave;
+sync_with_master;
+--disable_query_log
+select "--- On slave --" as "";
+--enable_query_log
+select a,b, truncate(rand_value,4) from t1;
+select * from t2;
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+connection master;
+drop table t1,t2,t3;
+
+#
+# #12480: NOW() is not constant in a trigger
+# #12481: Using NOW() in a stored function breaks statement based replication
+#
+
+# Start by getting a lock on 'bug12480' to be able to use get_lock() as sleep()
+connect (con2,localhost,root,,);
+connection con2;
+select get_lock("bug12480",2);
+connection default;
+
+create table t1 (a datetime,b datetime, c datetime);
+--ignore_warnings
+drop function if exists bug12480;
+--enable_warnings
+
+delimiter |;
+
+create function bug12480() returns datetime
+begin
+ set @a=get_lock("bug12480",2);
+ return now();
+end|
+
+create trigger t1_first before insert on t1
+for each row begin
+ set @a=get_lock("bug12480",2);
+ set new.b= now();
+ set new.c= bug12480();
+end
+|
+
+delimiter ;|
+insert into t1 set a = now();
+select a=b && a=c from t1;
+let $time=`select a from t1`;
+
+save_master_pos;
+connection slave;
+sync_with_master;
+--disable_query_log
+select "--- On slave --" as "";
+--enable_query_log
+select a=b && a=c from t1;
+--disable_query_log
+eval select a='$time' as 'test' from t1;
+--enable_query_log
+
+connection master;
+disconnect con2;
+
+truncate table t1;
+drop trigger t1_first;
+
+insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now());
+select a=b && a=c from t1;
+
+drop function bug12480;
+drop table t1;
+
+#
+# End of test
+#
+save_master_pos;
+connection slave;
+sync_with_master;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index eac76749589..ebd382b1df1 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -1542,6 +1542,11 @@ select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.
select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null;
explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null;
+
+select companynr,companyname from t2 left join t4 using (companynr) where companynr is null;
+select count(*) from t2 left join t4 using (companynr) where companynr is not null;
+explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null;
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null;
delete from t2 where fld1=999999;
#
@@ -1550,11 +1555,19 @@ delete from t2 where fld1=999999;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
+
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0;
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0;
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0;
# Following can't be optimized
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0;
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null;
+explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0;
+explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0;
+
#
# Joins with forms.
#
@@ -2348,3 +2361,98 @@ DROP TABLE t1,t2;
#
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
+
+#
+# Bug #11398 Bug in field_conv() results in wrong result of join with index
+#
+create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null);
+create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4));
+insert into t1 values (" 2", 2);
+insert into t2 values (" 2", " one "),(" 2", " two ");
+select * from t1 left join t2 on f1 = f3;
+drop table t1,t2;
+
+#
+# Bug #6558 Views: CREATE VIEW fails with JOIN ... USING
+#
+
+create table t1 (empnum smallint, grp int);
+create table t2 (empnum int, name char(5));
+insert into t1 values(1,1);
+insert into t2 values(1,'bob');
+create view v1 as select * from t2 inner join t1 using (empnum);
+select * from v1;
+drop table t1,t2;
+drop view v1;
+
+#
+# Bug #10646 Columns included in the join between two tables are ambigious
+# in the select
+#
+
+create table t1 (pk int primary key, b int);
+create table t2 (pk int primary key, c int);
+select pk from t1 inner join t2 using (pk);
+drop table t1,t2;
+
+#
+# Bug #10972 Natural join of view and underlying table gives wrong result
+#
+
+create table t1 (s1 int, s2 char(5), s3 decimal(10));
+create view v1 as select s1, s2, 'x' as s3 from t1;
+select * from t1 natural join v1;
+insert into t1 values (1,'x',5);
+select * from t1 natural join v1;
+drop table t1;
+drop view v1;
+
+#
+# Bug #6276 A SELECT that does a NATURAL OUTER JOIN without common
+# columns crashes server because of empty ON condition
+#
+
+create table t1(a1 int);
+create table t2(a2 int);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+create view v2 (c) as select a1 from t1;
+
+select * from t1 natural left join t2;
+select * from t1 natural right join t2;
+
+select * from v2 natural left join t2;
+select * from v2 natural right join t2;
+
+drop table t1, t2;
+drop view v2;
+
+
+#
+# Bug #4789 Incosistent results of more than 2-way natural joins due to
+# incorrect transformation to join ... on.
+#
+
+create table t1 (a int(10), t1_val int(10));
+create table t2 (b int(10), t2_val int(10));
+create table t3 (a int(10), b int(10));
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2),(3,3);
+insert into t3 values (1,1),(2,1),(3,1),(4,1);
+# the following two queries must return the same result
+select * from t1 natural join t2 natural join t3;
+select * from t1 natural join t3 natural join t2;
+drop table t1, t2, t3;
+
+
+#
+# Bug #6495 Illogical requirement for column qualification in NATURAL join
+#
+
+create table t1 (a char(1));
+create table t2 (a char(1));
+insert into t1 values ('a'),('b'),('c');
+insert into t2 values ('b'),('c'),('d');
+select a from t1 natural join t2;
+select * from t1 natural join t2 where a = 'b';
+drop table t1, t2;
diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test
index 1da700c9adf..481779e76d7 100644
--- a/mysql-test/t/select_safe.test
+++ b/mysql-test/t/select_safe.test
@@ -78,7 +78,7 @@ select * from (select * from t1) x;
set local max_join_size=1;
--error 1104
-select * from (select * from t1 a, t1 b) x;
+select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x;
set local max_join_size=1;
--error 1104
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index efe3504ad7d..b9fc991dc80 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -387,3 +387,26 @@ SHOW CREATE TABLE t1;
DROP TABLE t1;
# End of 4.1 tests
+#
+# BUG 12183 - SHOW OPEN TABLES behavior doesn't match grammar
+# First we close all open tables with FLUSH tables and then we open some.
+CREATE TABLE txt1(a int);
+CREATE TABLE tyt2(a int);
+CREATE TABLE urkunde(a int);
+FLUSH TABLES;
+SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0;
+SHOW OPEN TABLES;
+SHOW OPEN TABLES FROM mysql;
+SHOW OPEN TABLES FROM mysql LIKE 'u%';
+SHOW OPEN TABLES LIKE 't%';
+SHOW OPEN TABLES LIKE '%o%';
+FLUSH TABLES;
+SHOW OPEN TABLES;
+DROP TABLE txt1;
+DROP TABLE tyt2;
+DROP TABLE urkunde;
+#
+# BUG #12591 (SHOW TABLES FROM dbname produces wrong error message)
+#
+--error 1049
+SHOW TABLES FROM non_existing_database;
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 7f567449311..f68ea1b31a3 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -334,7 +334,7 @@ begin
end|
# USE is not allowed
---error 1336
+--error ER_SP_BADSTATEMENT
create procedure u()
use sptmp|
@@ -410,6 +410,35 @@ unlock tables|
#
+# Check that in functions we don't allow to update tables which
+# are used by statements which invoke these functions.
+#
+--disable_warnings
+drop function if exists f1|
+--enable_warnings
+create function f1(i int) returns int
+begin
+ insert into t1 (val) values (i);
+ return 0;
+end|
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+select val, f1(val) from t1|
+# Table alias should not matter
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+select val, f1(val) from t1 as tab|
+select * from t1|
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+update t1 set val= f1(val)|
+select * from t1|
+# But this should be OK
+select f1(17)|
+select * from t1|
+# Cleanup
+delete from t1 where val= 17|
+drop function f1|
+
+
+#
# BUG#1965
#
create procedure bug1965()
@@ -811,19 +840,19 @@ end|
#
# Some things are caught when parsing
---error ER_SP_NO_RETSET_IN_FUNC
+--error ER_SP_NO_RETSET
create function bug8408() returns int
begin
select * from t1;
return 0;
end|
---error ER_SP_NO_RETSET_IN_FUNC
+--error ER_SP_NO_RETSET
create function bug8408() returns int
begin
show warnings;
return 0;
end|
---error ER_SP_NO_RETSET_IN_FUNC
+--error ER_SP_NO_RETSET
create function bug8408(a int) returns int
begin
declare b int;
@@ -885,7 +914,7 @@ create procedure bug10537()
--disable_warnings
drop function if exists bug8409|
--enable_warnings
---error ER_SP_BADSTATEMENT
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409()
returns int
begin
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index 15fcba5ebe9..6f1332f80d5 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -371,3 +371,45 @@ drop procedure bug7291_0;
disconnect user1;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop user user1@localhost;
+
+#
+# Bug #12318: Wrong error message when accessing an inaccessible stored
+# procedure in another database when the current database is
+# information_schema.
+#
+
+--disable_warnings
+drop database if exists mysqltest_1;
+--enable_warnings
+
+create database mysqltest_1;
+delimiter //;
+create procedure mysqltest_1.p1()
+begin
+ select 1 from dual;
+end//
+delimiter ;//
+
+grant usage on *.* to mysqltest_1@localhost;
+
+connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection n1;
+--error 1370
+call mysqltest_1.p1();
+disconnect n1;
+# Test also without a current database
+connect (n2,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection n2;
+--error 1370
+call mysqltest_1.p1();
+disconnect n2;
+
+connection default;
+
+drop procedure mysqltest_1.p1;
+drop database mysqltest_1;
+
+revoke usage on *.* from mysqltest_1@localhost;
+drop user mysqltest_1@localhost;
+
+# End of 5.0 bugs.
diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test
index 4c192f3e96f..70c1efb1f0b 100644
--- a/mysql-test/t/sp-threads.test
+++ b/mysql-test/t/sp-threads.test
@@ -5,6 +5,7 @@
connect (con1root,localhost,root,,);
connect (con2root,localhost,root,,);
+connect (con3root,localhost,root,,);
connection con1root;
use test;
@@ -75,7 +76,7 @@ send call bug9486();
connection con2root;
--sleep 2
# There should be call statement in locked state.
---replace_column 1 # 6 #
+--replace_column 1 # 3 localhost 6 #
show processlist;
unlock tables;
connection con1root;
@@ -130,6 +131,48 @@ drop function bug11554;
drop table t1;
drop view v1;
+
+# BUG#12228
+--disable_warnings
+drop procedure if exists p1;
+drop procedure if exists p2;
+--enable_warnings
+
+connection con1root;
+delimiter |;
+create table t1 (s1 int)|
+create procedure p1() select * from t1|
+create procedure p2()
+begin
+ insert into t1 values (1);
+ call p1();
+ select * from t1;
+end|
+delimiter ;|
+
+connection con2root;
+use test;
+lock table t1 write;
+
+connection con1root;
+send call p2();
+
+connection con3root;
+use test;
+drop procedure p1;
+create procedure p1() select * from t1;
+
+connection con2root;
+unlock tables;
+
+connection con1root;
+# Crash will be here if we hit BUG#12228
+reap;
+
+drop procedure p1;
+drop procedure p2;
+drop table t1;
+
#
# BUG#NNNN: New bug synopsis
#
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index fe1dc613249..abff597405b 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -2468,25 +2468,26 @@ drop table t3|
#
# BUG#4318
#
-#QQ Don't know if HANDLER commands can work with SPs, or at all...
-#
-#create table t3 (s1 int)|
-#insert into t3 values (3), (4)|
-#
-#--disable_warnings
-#drop procedure if exists bug4318|
-#--enable_warnings
-#create procedure bug4318()
-# handler t3 read next|
-#
-#handler t3 open|
-## Expect no results, as tables are closed, but there shouldn't be any errors
-#call bug4318()|
-#call bug4318()|
-#handler t3 close|
-#
-#drop procedure bug4318|
-#drop table t3|
+
+--disable_parsing Don't know if HANDLER commands can work with SPs, or at all..
+create table t3 (s1 int)|
+insert into t3 values (3), (4)|
+
+--disable_warnings
+drop procedure if exists bug4318|
+--enable_warnings
+create procedure bug4318()
+ handler t3 read next|
+
+handler t3 open|
+# Expect no results, as tables are closed, but there shouldn't be any errors
+call bug4318()|
+call bug4318()|
+handler t3 close|
+
+drop procedure bug4318|
+drop table t3|
+--enable_parsing
#
# BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error
@@ -2542,9 +2543,9 @@ create procedure bug4902_2()
begin
show processlist;
end|
---replace_column 1 # 6 #
+--replace_column 1 # 6 # 3 localhost
call bug4902_2()|
---replace_column 1 # 6 #
+--replace_column 1 # 6 # 3 localhost
call bug4902_2()|
drop procedure bug4902_2|
@@ -2834,26 +2835,27 @@ drop table t3|
#
# BUG#6022: Stored procedure shutdown problem with self-calling function.
#
-# This part of test is disabled until we implement support for
-# recursive stored functions.
-#--disable_warnings
-#drop function if exists bug6022|
-#--enable_warnings
-#
-#--disable_warnings
-#drop function if exists bug6022|
-#--enable_warnings
-#create function bug6022(x int) returns int
-#begin
-# if x < 0 then
-# return 0;
-# else
-# return bug6022(x-1);
-# end if;
-#end|
-#
-#select bug6022(5)|
-#drop function bug6022|
+
+--disable_parsing until we implement support for recursive stored functions.
+--disable_warnings
+drop function if exists bug6022|
+--enable_warnings
+
+--disable_warnings
+drop function if exists bug6022|
+--enable_warnings
+create function bug6022(x int) returns int
+begin
+ if x < 0 then
+ return 0;
+ else
+ return bug6022(x-1);
+ end if;
+end|
+
+select bug6022(5)|
+drop function bug6022|
+--enable_parsing
#
# BUG#6029: Stored procedure specific handlers should have priority
@@ -3760,27 +3762,28 @@ drop procedure if exists bug7088_1|
drop procedure if exists bug7088_2|
--enable_warnings
-# psergey: temporarily disabled until Bar fixes BUG#11986
-# create procedure bug6063()
-# lâbel: begin end|
-# call bug6063()|
-# # QQ Known bug: this will not show the label correctly.
-# show create procedure bug6063|
-#
-# set character set utf8|
-# create procedure bug7088_1()
-# label1: begin end label1|
-# create procedure bug7088_2()
-# läbel1: begin end|
-# call bug7088_1()|
-# call bug7088_2()|
-# set character set default|
-# show create procedure bug7088_1|
-# show create procedure bug7088_2|
-#
-# drop procedure bug6063|
-# drop procedure bug7088_1|
-# drop procedure bug7088_2|
+--disable_parsing temporarily disabled until Bar fixes BUG#11986
+create procedure bug6063()
+ lâbel: begin end|
+call bug6063()|
+# QQ Known bug: this will not show the label correctly.
+show create procedure bug6063|
+
+set character set utf8|
+create procedure bug7088_1()
+ label1: begin end label1|
+create procedure bug7088_2()
+ läbel1: begin end|
+call bug7088_1()|
+call bug7088_2()|
+set character set default|
+show create procedure bug7088_1|
+show create procedure bug7088_2|
+
+drop procedure bug6063|
+drop procedure bug7088_1|
+drop procedure bug7088_2|
+--enable_parsing
#
# BUG#9565: "Wrong locking in stored procedure if a sub-sequent procedure
@@ -3854,6 +3857,146 @@ drop procedure bug8692|
drop table t3|
#
+# Bug#10055 "Using stored function with information_schema causes empty
+# result set"
+#
+--disable_warnings
+drop function if exists bug10055|
+--enable_warnings
+create function bug10055(v char(255)) returns char(255) return lower(v)|
+# This select should not crash server and should return all fields in t1
+select t.column_name, bug10055(t.column_name)
+from information_schema.columns as t
+where t.table_schema = 'test' and t.table_name = 't1'|
+drop function bug10055|
+
+#
+# Bug #12297 "SP crashes the server if data inserted inside a lon loop"
+# The test for memleak bug, so actually there is no way to test it
+# from the suite. The test below could be used to check SP memory
+# consumption by passing large input parameter.
+#
+
+#
+# Note: the test is currenly disabled because of the
+# Bug #12637: SP crashes the server if it has update query with user var
+# & binlog is enabled.
+#
+
+--disable_warnings
+#drop procedure if exists bug12297|
+--enable_warnings
+
+#create procedure bug12297(lim int)
+#begin
+# set @x = 0;
+# repeat
+# insert into t1(id,data)
+# values('aa', @x);
+# set @x = @x + 1;
+# until @x >= lim
+# end repeat;
+#end|
+
+#call bug12297(10)|
+#drop procedure bug12297|
+
+#
+# Bug #11247 "Stored procedures: Function calls in long loops leak memory"
+# One more memleak bug test. One could use this test to check that the memory
+# isn't leaking by increasing the input value for p_bug11247.
+#
+
+--disable_warnings
+drop function if exists f_bug11247|
+drop procedure if exists p_bug11247|
+--enable_warnings
+
+create function f_bug11247(param int)
+ returns int
+return param + 1|
+
+create procedure p_bug11247(lim int)
+begin
+ declare v int default 0;
+
+ while v < lim do
+ set v= f_bug11247(v);
+ end while;
+end|
+
+call p_bug11247(10)|
+drop function f_bug11247|
+drop procedure p_bug11247|
+#
+# BUG#12168: "'DECLARE CONTINUE HANDLER FOR NOT FOUND ...' in conditional
+# handled incorrectly"
+#
+--disable_warnings
+drop procedure if exists bug12168|
+drop table if exists t3, t4|
+--enable_warnings
+
+create table t3 (a int)|
+insert into t3 values (1),(2),(3),(4)|
+
+create table t4 (a int)|
+
+create procedure bug12168(arg1 char(1))
+begin
+ declare b, c integer;
+ if arg1 = 'a' then
+ begin
+ declare c1 cursor for select a from t3 where a % 2;
+ declare continue handler for not found set b = 1;
+ set b = 0;
+ open c1;
+ c1_repeat: repeat
+ fetch c1 into c;
+ if (b = 1) then
+ leave c1_repeat;
+ end if;
+
+ insert into t4 values (c);
+ until b = 1
+ end repeat;
+ end;
+ end if;
+ if arg1 = 'b' then
+ begin
+ declare c2 cursor for select a from t3 where not a % 2;
+ declare continue handler for not found set b = 1;
+ set b = 0;
+ open c2;
+ c2_repeat: repeat
+ fetch c2 into c;
+ if (b = 1) then
+ leave c2_repeat;
+ end if;
+
+ insert into t4 values (c);
+ until b = 1
+ end repeat;
+ end;
+ end if;
+end|
+
+call bug12168('a')|
+select * from t4|
+truncate t4|
+call bug12168('b')|
+select * from t4|
+truncate t4|
+call bug12168('a')|
+select * from t4|
+truncate t4|
+call bug12168('b')|
+select * from t4|
+truncate t4|
+drop table t3, t4|
+drop procedure if exists bug12168|
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 41cdf9f1c64..5020902009d 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -696,7 +696,7 @@ CREATE TABLE `t1` (
INSERT INTO t1 VALUES (1);
UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i));
UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i));
--- error 1109
+-- error 1054
UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t);
select * from t1;
drop table t1;
@@ -1005,7 +1005,7 @@ create table t2 (s1 int);
select * from t1 where (select count(*) from t2 where t1.s2) = 1;
-- error 1054
select * from t1 where (select count(*) from t2 group by t1.s2) = 1;
--- error 1109
+-- error 1054
select count(*) from t2 group by t1.s2;
drop table t1, t2;
@@ -1133,7 +1133,9 @@ CREATE TABLE t2 (id INT);
INSERT INTO t1 VALUES (1), (2);
INSERT INTO t2 VALUES (1);
SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id);
+SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id);
SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id;
+SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id;
DROP TABLE t1,t2;
#
@@ -1726,9 +1728,102 @@ select (select a from t1) = (1,2);
select (1,2,3) = (select * from t1);
-- error 1241
select (select * from t1) = (1,2,3);
+drop table t1
+
+#
+# Item_int_with_ref check (BUG#10020)
+#
+CREATE TABLE `t1` (
+ `itemid` bigint(20) unsigned NOT NULL auto_increment,
+ `sessionid` bigint(20) unsigned default NULL,
+ `time` int(10) unsigned NOT NULL default '0',
+ `type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT
+NULL default '',
+ `data` text collate latin1_general_ci NOT NULL,
+ PRIMARY KEY (`itemid`)
+) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+INSERT INTO `t1` VALUES (1, 1, 1, 'D', '');
+CREATE TABLE `t2` (
+ `sessionid` bigint(20) unsigned NOT NULL auto_increment,
+ `pid` int(10) unsigned NOT NULL default '0',
+ `date` int(10) unsigned NOT NULL default '0',
+ `ip` varchar(15) collate latin1_general_ci NOT NULL default '',
+ PRIMARY KEY (`sessionid`)
+) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1');
+SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30;
+drop tables t1,t2;
+
+# BUG#11821 : Select from subselect using aggregate function on an enum
+# segfaults:
+create table t1 (fld enum('0','1'));
+insert into t1 values ('1');
+select * from (select max(fld) from t1) as foo;
drop table t1;
#
+# Bug #11867: queries with ROW(,elems>) IN (SELECT DISTINCT <cols> FROM ...)
+#
+
+CREATE TABLE t1 (one int, two int, flag char(1));
+CREATE TABLE t2 (one int, two int, flag char(1));
+INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N');
+INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N');
+
+SELECT * FROM t1
+ WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N');
+SELECT * FROM t1
+ WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N');
+
+insert into t2 values (null,null,'N');
+insert into t2 values (null,3,'0');
+insert into t2 values (null,5,'0');
+insert into t2 values (10,null,'0');
+insert into t1 values (10,3,'0');
+insert into t1 values (10,5,'0');
+insert into t1 values (10,10,'0');
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1;
+SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1;
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+DROP TABLE t1,t2;
+
+#
+# Bug #12392: where cond with IN predicate for rows and NULL values in table
+#
+
+CREATE TABLE t1 (a char(5), b char(5));
+INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa');
+
+SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb'));
+
+DROP TABLE t1;
+
+#
+# Bug #11479: subquery over left join with an empty inner table
+#
+
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int, b int);
+CREATE TABLE t3 (b int NOT NULL);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (1,10), (3,30);
+
+SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+ WHERE t3.b IS NOT NULL OR t2.a > 10;
+SELECT * FROM t1
+ WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+ WHERE t3.b IS NOT NULL OR t2.a > 10);
+
+DROP TABLE t1,t2,t3;
+
+# End of 4.1 tests
+
+#
#decimal-related tests
#
create table t1 (df decimal(5,1));
@@ -1868,4 +1963,3 @@ select * from (select max(fld) from t1) as foo;
drop table t1;
-# End of 4.1 tests
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 7bf8b1a4e2b..9920f203c94 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -7,6 +7,7 @@ drop table if exists t1, t2, t3;
drop view if exists v1;
drop database if exists mysqltest;
drop function if exists f1;
+drop procedure if exists p1;
--enable_warnings
create table t1 (i int);
@@ -642,3 +643,125 @@ show create table t1;
--replace_column 6 #
show triggers;
drop table t1;
+
+# Test for bug #12280 "Triggers: crash if flush tables"
+# FLUSH TABLES and FLUSH PRIVILEGES should be disallowed inside
+# of functions and triggers.
+create table t1 (id int);
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush tables;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush privileges;
+create procedure p1() flush tables;
+create trigger t1_ai after insert on t1 for each row call p1();
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+drop procedure p1;
+create procedure p1() flush privileges;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+drop procedure p1;
+drop table t1;
+
+# Test for bug #11973 "SELECT .. INTO var_name; in trigger cause
+# crash on update"
+
+create table t1 (id int, data int, username varchar(16));
+insert into t1 (id, data) values (1, 0);
+delimiter |;
+create trigger t1_whoupdated before update on t1 for each row
+begin
+ declare user varchar(32);
+ declare i int;
+ select user() into user;
+ set NEW.username = user;
+ select count(*) from ((select 1) union (select 2)) as d1 into i;
+end|
+delimiter ;|
+update t1 set data = 1;
+
+connect (addconroot, localhost, root,,);
+connection addconroot;
+update t1 set data = 2;
+
+connection default;
+disconnect addconroot;
+drop table t1;
+
+#
+# #11587 Trigger causes lost connection error
+#
+
+create table t1 (c1 int, c2 datetime);
+delimiter |;
+--error ER_SP_NO_RETSET
+create trigger tr1 before insert on t1 for each row
+begin
+ set new.c2= '2004-04-01';
+ select 'hello';
+end|
+delimiter ;|
+
+insert into t1 (c1) values (1),(2),(3);
+select * from t1;
+
+--disable_warnings
+drop procedure if exists bug11587;
+--enable_warnings
+
+delimiter |;
+create procedure bug11587(x char(16))
+begin
+ select "hello";
+ select "hello again";
+end|
+
+create trigger tr1 before insert on t1 for each row
+begin
+ call bug11587();
+ set new.c2= '2004-04-02';
+end|
+delimiter ;|
+
+--error 1312
+insert into t1 (c1) values (4),(5),(6);
+select * from t1;
+
+drop procedure bug11587;
+drop table t1;
+
+# Test for bug #11896 "Partial locking in case of recursive trigger
+# definitions". Recursion in triggers should not be allowed.
+# We also should not allow to change tables which are used in
+# statements invoking this trigger.
+create table t1 (f1 integer);
+create table t2 (f2 integer);
+create trigger t1_ai after insert on t1
+ for each row insert into t2 values (new.f1+1);
+create trigger t2_ai after insert on t2
+ for each row insert into t1 values (new.f2+1);
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+insert into t1 values (1);
+select * from t1;
+select * from t2;
+drop trigger t1_ai;
+drop trigger t2_ai;
+create trigger t1_bu before update on t1
+ for each row insert into t1 values (2);
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+update t1 set f1= 10;
+select * from t1;
+drop trigger t1_bu;
+create trigger t1_bu before update on t1
+ for each row delete from t1 where f1=new.f1;
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+update t1 set f1= 10;
+select * from t1;
+drop trigger t1_bu;
+# This should work tough
+create trigger t1_bi before insert on t1
+ for each row set new.f1=(select sum(f1) from t1);
+insert into t1 values (3);
+select * from t1;
+drop trigger t1_bi;
+drop tables t1, t2;
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
index fd5eb49858c..6906cfc2808 100644
--- a/mysql-test/t/type_bit.test
+++ b/mysql-test/t/type_bit.test
@@ -16,10 +16,10 @@ select 0 + b'1111111111111111';
select 0 + b'1000000000000001';
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
--enable_warnings
---error 1074
+--error 1439
create table t1 (a bit(65));
create table t1 (a bit(0));
diff --git a/mysql-test/t/type_bit_innodb.test b/mysql-test/t/type_bit_innodb.test
index 693fc169717..ec433f40a88 100644
--- a/mysql-test/t/type_bit_innodb.test
+++ b/mysql-test/t/type_bit_innodb.test
@@ -20,7 +20,7 @@ select 0 + b'1000000000000001';
drop table if exists t1;
--enable_warnings
---error 1074
+--error 1439
create table t1 (a bit(65)) engine=innodb;
create table t1 (a bit(0)) engine=innodb;
diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
index ca70e35d3cd..4b6741b4242 100644
--- a/mysql-test/t/type_datetime.test
+++ b/mysql-test/t/type_datetime.test
@@ -14,6 +14,17 @@ optimize table t1;
check table t1;
delete from t1;
insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000");
+
+# Strange dates
+insert into t1 values ("2003-003-03");
+
+# Bug #7308: ISO-8601 date format not handled correctly
+insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01");
+select * from t1;
+
+# Test some wrong dates
+truncate table t1;
+insert into t1 values("2003-0303 12:13:14");
select * from t1;
drop table t1;
@@ -102,14 +113,4 @@ insert into t1 values ("00-00-00"), ("00-00-00 00:00:00");
select * from t1;
drop table t1;
-#
-# Bug #7308: ISO-8601 date format not handled correctly
-#
-create table t1 (dt datetime);
-insert into t1 values ("20010101T010101");
-insert into t1 values ("2001-01-01T01:01:01");
-insert into t1 values ("2001-1-1T1:01:01");
-select * from t1;
-drop table t1;
-
# End of 4.1 tests
diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test
index c1a5ac382ec..03ee91f14d8 100644
--- a/mysql-test/t/type_ranges.test
+++ b/mysql-test/t/type_ranges.test
@@ -158,12 +158,19 @@ create table t2 ( id integer unsigned not null primary key );
insert into t1 values (1), (2);
insert into t2 values (1);
select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
+select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
create table t3 (id_A integer unsigned not null, id_B integer unsigned null );
insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
select * from t3;
+delete from t3;
+insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
+select * from t3;
drop table t3;
create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id );
select * from t3;
+drop table t3;
+create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id);
+select * from t3;
drop table t1,t2,t3;
# End of 4.1 tests
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index 227d1cddcfa..d4b0c1746af 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -276,7 +276,7 @@ create temporary table t1 select a from t1 union select a from t2;
drop temporary table t1;
--error 1093
create table t1 select a from t1 union select a from t2;
---error 1109
+--error 1054
select a from t1 union select a from t2 order by t2.a;
drop table t1,t2;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 9885566442f..4c11f93e683 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6;
drop view v1, v2, v3, v4, v5, v6;
drop table t2;
+--disable_warnings
+drop function if exists f1;
+drop function if exists f2;
+--enable_warnings
CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time);
CREATE TABLE t3 (col1 time);
@@ -1897,3 +1901,85 @@ SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM v1 GROUP BY pid;
DROP VIEW v1;
DROP TABLE t1,t2;
+
+#
+# Test for bug #12382: SELECT * FROM view after INSERT command
+#
+
+CREATE TABLE t1 (id int PRIMARY KEY, f varchar(255));
+CREATE VIEW v1 AS SELECT id, f FROM t1 WHERE id <= 2;
+INSERT INTO t1 VALUES (2, 'foo2');
+INSERT INTO t1 VALUES (1, 'foo1');
+
+SELECT * FROM v1;
+SELECT * FROM v1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# Test for bug #12470: crash for a simple select from a view defined
+# as a join over 5 tables
+
+CREATE TABLE t1 (pk int PRIMARY KEY, b int);
+CREATE TABLE t2 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t3 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t4 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE TABLE t5 (pk int PRIMARY KEY, fk int, INDEX idx(fk));
+CREATE VIEW v1 AS
+ SELECT t1.pk as a FROM t1,t2,t3,t4,t5
+ WHERE t1.b IS NULL AND
+ t1.pk=t2.fk AND t2.pk=t3.fk AND t3.pk=t4.fk AND t4.pk=t5.fk;
+
+SELECT a FROM v1;
+
+DROP VIEW v1;
+DROP TABLE t1,t2,t3,t4,t5;
+
+#
+# Bug #12298 Typo in function name results in erroneous view being created.
+#
+create view v1 as select timestampdiff(day,'1997-01-01 00:00:00','1997-01-02 00:00:00') as f1;
+select * from v1;
+drop view v1;
+
+#
+# Bug #10624 Views with multiple UNION and UNION ALL produce incorrect results
+#
+create table t1 (f1 int);
+create table t2 (f1 int);
+insert into t1 values (1);
+insert into t2 values (2);
+create view v1 as select * from t1 union select * from t2 union all select * from t2;
+select * from v1;
+drop view v1;
+drop table t1,t2;
+#
+# Test for bug #10970: view referring a temporary table indirectly
+#
+
+CREATE TEMPORARY TABLE t1 (a int);
+CREATE FUNCTION f1 () RETURNS int RETURN (SELECT COUNT(*) FROM t1);
+-- error 1352
+CREATE VIEW v1 AS SELECT f1();
+
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+#
+# BUG #12533 (crash on DESCRIBE <view> after renaming base table column)
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+--enable_warnings
+
+CREATE TABLE t1 (f4 CHAR(5));
+CREATE VIEW v1 AS SELECT * FROM t1;
+DESCRIBE v1;
+
+ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5);
+--error 1356
+DESCRIBE v1;
+DROP TABLE t1;
+DROP VIEW v1;
diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test
index 321e5008035..1347fd05415 100644
--- a/mysql-test/t/xa.test
+++ b/mysql-test/t/xa.test
@@ -31,6 +31,9 @@ xa end 'testa','testb';
connect (con1,localhost,,,);
connection con1;
+--error 1440
+xa start 'testa','testb';
+
# gtrid [ , bqual [ , formatID ] ]
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
@@ -47,6 +50,7 @@ xa prepare 'testa','testb';
xa recover;
+--error 1397
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 6b983dc38dd..7bfcb21c4ad 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -30,7 +30,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c \
- mf_keycache.c mf_keycaches.c my_crc32.c \
+ mf_keycaches.c my_crc32.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
diff --git a/mysys/charset.c b/mysys/charset.c
index 701170b747b..c02144fafc0 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -679,6 +679,32 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
}
+#ifdef BACKSLASH_MBTAIL
+static CHARSET_INFO *fs_cset_cache= NULL;
+
+CHARSET_INFO *fs_character_set()
+{
+ if (!fs_cset_cache)
+ {
+ char buf[10]= "cp";
+ GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
+ buf+2, sizeof(buf)-3);
+ /*
+ We cannot call get_charset_by_name here
+ because fs_character_set() is executed before
+ LOCK_THD_charset mutex initialization, which
+ is used inside get_charset_by_name.
+ As we're now interested in cp932 only,
+ let's just detect it using strcmp().
+ */
+ fs_cset_cache= !strcmp(buf, "cp932") ?
+ &my_charset_cp932_japanese_ci : &my_charset_bin;
+ }
+ return fs_cset_cache;
+}
+#endif
+
+
/*
Escape apostrophes by doubling them up
diff --git a/mysys/list.c b/mysys/list.c
index c3cd6c94b9f..0e55c9399f5 100644
--- a/mysys/list.c
+++ b/mysys/list.c
@@ -109,7 +109,7 @@ int list_walk(LIST *list, list_walk_action action, gptr argument)
{
if ((error = (*action)(list->data,argument)))
return error;
- list=rest(list);
+ list=list_rest(list);
}
return 0;
}
diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c
index 3de82c05b87..45bf4d56c31 100644
--- a/mysys/mf_dirname.c
+++ b/mysys/mf_dirname.c
@@ -22,6 +22,9 @@
uint dirname_length(const char *name)
{
register my_string pos,gpos;
+#ifdef BASKSLASH_MBTAIL
+ CHARSET_INFO *fs= fs_character_set();
+#endif
#ifdef FN_DEVCHAR
if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0)
#endif
@@ -29,12 +32,22 @@ uint dirname_length(const char *name)
gpos= pos++;
for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
+ {
+#ifdef BASKSLASH_MBTAIL
+ uint l;
+ if (use_mb(fs) && (l= my_ismbchar(fs, pos, pos + 3)))
+ {
+ pos+= l - 1;
+ continue;
+ }
+#endif
if (*pos == FN_LIBCHAR || *pos == '/'
#ifdef FN_C_AFTER_DIR
|| *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
#endif
)
gpos=pos;
+ }
return ((uint) (uint) (gpos+1-(char*) name));
}
@@ -85,6 +98,9 @@ uint dirname_part(my_string to, const char *name)
char *convert_dirname(char *to, const char *from, const char *from_end)
{
char *to_org=to;
+#ifdef BACKSLASH_MBTAIL
+ CHARSET_INFO *fs= fs_character_set();
+#endif
/* We use -2 here, becasue we need place for the last FN_LIBCHAR */
if (!from_end || (from_end - from) > FN_REFLEN-2)
@@ -103,7 +119,22 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
*to++= FN_C_AFTER_DIR;
#endif
else
- *to++= *from;
+ {
+#ifdef BACKSLASH_MBTAIL
+ uint l;
+ if (use_mb(fs) && (l= my_ismbchar(fs, from, from + 3)))
+ {
+ memmove(to, from, l);
+ to+= l;
+ from+= l - 1;
+ to_org= to; /* Don't look inside mbchar */
+ }
+ else
+#endif
+ {
+ *to++= *from;
+ }
+ }
}
*to=0;
}
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index b12e68cc1f9..8998da8aefa 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -54,7 +54,7 @@ void get_date(register my_string to, int flag, time_t date)
if (flag & GETDATE_GMT)
start_time= localtime(&skr);
else
- gmtime(&skr,&tm_tmp);
+ start_time= gmtime(&skr);
#endif
if (flag & GETDATE_SHORT_DATE)
sprintf(to,"%02d%02d%02d",
diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c
index 86172f648f4..049aa59a578 100644
--- a/mysys/mf_pack.c
+++ b/mysys/mf_pack.c
@@ -124,6 +124,9 @@ uint cleanup_dirname(register my_string to, const char *from)
reg4 my_string start;
char parent[5], /* for "FN_PARENTDIR" */
buff[FN_REFLEN+1],*end_parentdir;
+#ifdef BACKSLASH_MBTAIL
+ CHARSET_INFO *fs= fs_character_set();
+#endif
DBUG_ENTER("cleanup_dirname");
DBUG_PRINT("enter",("from: '%s'",from));
@@ -141,6 +144,15 @@ uint cleanup_dirname(register my_string to, const char *from)
length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
{
+#ifdef BACKSLASH_MBTAIL
+ uint l;
+ if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
+ {
+ for (l-- ; l ; *++pos= *from_ptr++, l--);
+ start= pos + 1; /* Don't look inside multi-byte char */
+ continue;
+ }
+#endif
if (*pos == '/')
*pos = FN_LIBCHAR;
if (*pos == FN_LIBCHAR)
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 410cb2e7ee7..abb1ad27f7b 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -395,7 +395,7 @@ static void netware_init()
}
/* Parse program name and change to base format */
- name= my_progname;
+ name= (char*) my_progname;
for (; *name; name++)
{
if (*name == '\\')
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index c076e8934ad..41266d61b0a 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -1206,7 +1206,8 @@ void thr_print_locks(void)
pthread_mutex_lock(&THR_LOCK_lock);
puts("Current locks:");
- for (list=thr_lock_thread_list ; list && count++ < MAX_THREADS ; list=rest(list))
+ for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
+ list= list_rest(list))
{
THR_LOCK *lock=(THR_LOCK*) list->data;
VOID(pthread_mutex_lock(&lock->mutex));
diff --git a/ndb/include/kernel/signaldata/ApiBroadcast.hpp b/ndb/include/kernel/signaldata/ApiBroadcast.hpp
new file mode 100644
index 00000000000..8050326ce78
--- /dev/null
+++ b/ndb/include/kernel/signaldata/ApiBroadcast.hpp
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef API_BROADCAST_HPP
+#define API_BROADCAST_HPP
+
+#include "SignalData.hpp"
+
+struct ApiBroadcastRep
+{
+ STATIC_CONST( SignalLength = 2 );
+
+ Uint32 gsn;
+ Uint32 minVersion;
+ Uint32 theData[1];
+};
+
+#endif
diff --git a/ndb/src/kernel/vm/KeyDescriptor.hpp b/ndb/src/kernel/vm/KeyDescriptor.hpp
new file mode 100644
index 00000000000..456d64ce1d8
--- /dev/null
+++ b/ndb/src/kernel/vm/KeyDescriptor.hpp
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef KEY_DESCRIPTOR_HPP
+#define KEY_DESCRIPTOR_HPP
+
+#include <ndb_types.h>
+#include <ndb_limits.h>
+#include "CArray.hpp"
+
+struct KeyDescriptor
+{
+ KeyDescriptor () { noOfKeyAttr = hasCharAttr = noOfDistrKeys = 0; }
+
+ Uint8 noOfKeyAttr;
+ Uint8 hasCharAttr;
+ Uint8 noOfDistrKeys;
+ Uint8 unused;
+ struct KeyAttr
+ {
+ Uint32 attributeDescriptor;
+ CHARSET_INFO* charsetInfo;
+ } keyAttr[MAX_ATTRIBUTES_IN_INDEX];
+};
+
+extern CArray<KeyDescriptor> g_key_descriptor_pool;
+
+#endif
diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh
index 7147fa9af42..66a1e2a4d62 100644
--- a/scripts/make_win_src_distribution.sh
+++ b/scripts/make_win_src_distribution.sh
@@ -343,8 +343,8 @@ mv $BASE/sql/sql_yacc.cpp-new $BASE/sql/sql_yacc.cpp
# Search the tree for plain text files and adapt the line end marker
#
find $BASE \( -name "*.dsp" -o -name "*.dsw" -o -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 COPYING -o -name ChangeLog -o -name EXCEPTIONS-CLIENT \
+ -o -name "INSTALL*" -o -name LICENSE -o -name "README*" \
-o -name "*.vcproj" -o -name "*.sln" \) -type f -print \
| while read v
do
diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp
index b6195d15603..e040a5da8c2 100644
--- a/server-tools/instance-manager/IMService.cpp
+++ b/server-tools/instance-manager/IMService.cpp
@@ -44,28 +44,28 @@ int HandleServiceOptions(Options options)
if (options.install_as_service)
{
if (winService.IsInstalled())
- log_info("Service is already installed\n");
+ log_info("Service is already installed");
else if (winService.Install())
- log_info("Service installed successfully\n");
+ log_info("Service installed successfully");
else
{
- log_info("Service failed to install\n");
- ret_val= -1;
+ log_info("Service failed to install");
+ ret_val= 1;
}
}
else if (options.remove_service)
{
if (! winService.IsInstalled())
- log_info("Service is not installed\n");
+ log_info("Service is not installed");
else if (winService.Remove())
- log_info("Service removed successfully\n");
+ log_info("Service removed successfully");
else
{
- log_info("Service failed to remove\n");
- ret_val= -1;
+ log_info("Service failed to remove");
+ ret_val= 1;
}
}
else
- return (int)winService.Init();
+ ret_val= !winService.Init();
return ret_val;
}
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index dee3c2d4e38..0a373429d01 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -36,6 +36,16 @@
#include <m_string.h>
#include <mysql.h>
+
+static void start_and_monitor_instance(Instance_options *old_instance_options,
+ Instance_map *instance_map);
+
+#ifndef _WIN_
+typedef pid_t My_process_info;
+#else
+typedef PROCESS_INFORMATION My_process_info;
+#endif
+
C_MODE_START
/*
@@ -48,13 +58,224 @@ C_MODE_START
pthread_handler_decl(proxy, arg)
{
Instance *instance= (Instance *) arg;
- instance->fork_and_monitor();
+ start_and_monitor_instance(&instance->options,
+ instance->get_map());
return 0;
}
C_MODE_END
+/*
+ Wait for an instance
+
+ SYNOPSYS
+ wait_process()
+ pi Pointer to the process information structure
+ (platform-dependent).
+
+ RETURN
+ 0 - Success
+ 1 - Error
+*/
+
+#ifndef __WIN__
+static int wait_process(My_process_info *pi)
+{
+ /*
+ Here we wait for the child created. This process differs for systems
+ running LinuxThreads and POSIX Threads compliant systems. This is because
+ according to POSIX we could wait() for a child in any thread of the
+ process. While LinuxThreads require that wait() is called by the thread,
+ which created the child.
+ On the other hand we could not expect mysqld to return the pid, we
+ got in from fork(), to wait4() fucntion when running on LinuxThreads.
+ This is because MySQL shutdown thread is not the one, which was created
+ by our fork() call.
+ So basically we have two options: whether the wait() call returns only in
+ the creator thread, but we cannot use waitpid() since we have no idea
+ which pid we should wait for (in fact it should be the pid of shutdown
+ thread, but we don't know this one). Or we could use waitpid(), but
+ couldn't use wait(), because it could return in any wait() in the program.
+ */
+ if (linuxthreads)
+ wait(NULL); /* LinuxThreads were detected */
+ else
+ waitpid(*pi, NULL, 0);
+
+ return 0;
+}
+#else
+static int wait_process(My_process_info *pi)
+{
+ /* Wait until child process exits. */
+ WaitForSingleObject(pi->hProcess, INFINITE);
+
+ DWORD exitcode;
+ ::GetExitCodeProcess(pi->hProcess, &exitcode);
+
+ /* Close process and thread handles. */
+ CloseHandle(pi->hProcess);
+ CloseHandle(pi->hThread);
+
+ /*
+ GetExitCodeProces returns zero on failure. We should revert this value
+ to report an error.
+ */
+ return (!exitcode);
+}
+#endif
+
+
+/*
+ Launch an instance
+
+ SYNOPSYS
+ start_process()
+ instance_options Pointer to the options of the instance to be
+ launched.
+ pi Pointer to the process information structure
+ (platform-dependent).
+
+ RETURN
+ 0 - Success
+ 1 - Cannot create an instance
+*/
+
+#ifndef __WIN__
+static int start_process(Instance_options *instance_options,
+ My_process_info *pi)
+{
+ *pi= fork();
+
+ switch (*pi) {
+ case 0:
+ execv(instance_options->mysqld_path, instance_options->argv);
+ /* exec never returns */
+ exit(1);
+ case 1:
+ log_info("cannot fork() to start instance %s",
+ instance_options->instance_name);
+ return 1;
+ }
+ return 0;
+}
+#else
+static int start_process(Instance_options *instance_options,
+ My_process_info *pi)
+{
+ STARTUPINFO si;
+
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb= sizeof(STARTUPINFO);
+ ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
+
+ int cmdlen= 0;
+ for (int i= 1; instance_options->argv[i] != 0; i++)
+ cmdlen+= strlen(instance_options->argv[i]) + 1;
+ cmdlen++; /* we have to add a single space for CreateProcess (see docs) */
+
+ char *cmdline= NULL;
+ if (cmdlen > 0)
+ {
+ cmdline= new char[cmdlen];
+ cmdline[0]= 0;
+ for (int i= 1; instance_options->argv[i] != 0; i++)
+ {
+ strcat(cmdline, " ");
+ strcat(cmdline, instance_options->argv[i]);
+ }
+ }
+
+ /* Start the child process */
+ BOOL result=
+ CreateProcess(instance_options->mysqld_path, /* File to execute */
+ cmdline, /* Command line */
+ NULL, /* Process handle not inheritable */
+ NULL, /* Thread handle not inheritable */
+ FALSE, /* Set handle inheritance to FALSE */
+ 0, /* No creation flags */
+ NULL, /* Use parent's environment block */
+ NULL, /* Use parent's starting directory */
+ &si, /* Pointer to STARTUPINFO structure */
+ pi); /* Pointer to PROCESS_INFORMATION structure */
+ delete cmdline;
+
+ return (!result);
+}
+#endif
+
+/*
+ Fork child, exec an instance and monitor it.
+
+ SYNOPSYS
+ start_and_monitor_instance()
+ old_instance_options Pointer to the options of the instance to be
+ launched. This info is likely to become obsolete
+ when function returns from wait_process()
+ instance_map Pointer to the instance_map. We use it to protect
+ the instance from deletion, while we are working
+ with it.
+
+ DESCRIPTION
+ Fork a child, then exec and monitor it. When the child is dead,
+ find appropriate instance (for this purpose we save its name),
+ set appropriate flags and wake all threads waiting for instance
+ to stop.
+
+ RETURN
+ Function returns no value
+*/
+
+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 *current_instance;
+ My_process_info process_info;
+
+ /*
+ Lock instance map to guarantee that no instances are deleted during
+ strmake() and execv() calls.
+ */
+ instance_map->lock();
+
+ /*
+ 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);
+
+ if (start_process(old_instance_options, &process_info))
+ return; /* error is logged */
+
+ /* allow users to delete instances */
+ instance_map->unlock();
+
+ /* don't check for return value */
+ wait_process(&process_info);
+
+ current_instance= instance_map->find(instance_name_buff, instance_name_len);
+
+ if (current_instance)
+ current_instance->set_crash_flag_n_wake_all();
+
+ return;
+}
+
+
+Instance_map *Instance::get_map()
+{
+ return instance_map;
+}
+
+
void Instance::remove_pid()
{
int pid;
@@ -65,6 +286,7 @@ void Instance::remove_pid()
options.instance_name);
}
+
/*
The method starts an instance.
@@ -116,107 +338,24 @@ int Instance::start()
return ER_INSTANCE_ALREADY_STARTED;
}
-#ifndef __WIN__
-int Instance::launch_and_wait()
-{
- pid_t pid= fork();
-
- switch (pid) {
- case 0:
- execv(options.mysqld_path, options.argv);
- /* exec never returns */
- exit(1);
- case -1:
- log_info("cannot fork() to start instance %s", options.instance_name);
- return -1;
- default:
- /*
- Here we wait for the child created. This process differs for systems
- running LinuxThreads and POSIX Threads compliant systems. This is because
- according to POSIX we could wait() for a child in any thread of the
- process. While LinuxThreads require that wait() is called by the thread,
- which created the child.
- On the other hand we could not expect mysqld to return the pid, we
- got in from fork(), to wait4() fucntion when running on LinuxThreads.
- This is because MySQL shutdown thread is not the one, which was created
- by our fork() call.
- So basically we have two options: whether the wait() call returns only in
- the creator thread, but we cannot use waitpid() since we have no idea
- which pid we should wait for (in fact it should be the pid of shutdown
- thread, but we don't know this one). Or we could use waitpid(), but
- couldn't use wait(), because it could return in any wait() in the program.
- */
- if (linuxthreads)
- wait(NULL); /* LinuxThreads were detected */
- else
- waitpid(pid, NULL, 0);
- }
- return 0;
-}
-#else
-int Instance::launch_and_wait()
-{
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
- ZeroMemory(&si, sizeof(si));
- si.cb= sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
-
- int cmdlen= 0;
- for (int i= 1; options.argv[i] != 0; i++)
- cmdlen+= strlen(options.argv[i]) + 1;
- cmdlen++; // we have to add a single space for CreateProcess (read the docs)
-
- char *cmdline= NULL;
- if (cmdlen > 0)
- {
- cmdline= new char[cmdlen];
- cmdline[0]= 0;
- for (int i= 1; options.argv[i] != 0; i++)
- {
- strcat(cmdline, " ");
- strcat(cmdline, options.argv[i]);
- }
- }
-
- // Start the child process.
- BOOL result= CreateProcess(options.mysqld_path, // file to execute
- cmdline, // Command line.
- NULL, // Process handle not inheritable.
- NULL, // Thread handle not inheritable.
- FALSE, // Set handle inheritance to FALSE.
- 0, // No creation flags.
- NULL, // Use parent's environment block.
- NULL, // Use parent's starting directory.
- &si, // Pointer to STARTUPINFO structure.
- &pi ); // Pointer to PROCESS_INFORMATION structure.
- delete cmdline;
- if (! result)
- return -1;
-
- // Wait until child process exits.
- WaitForSingleObject(pi.hProcess, INFINITE);
-
- DWORD exitcode;
- ::GetExitCodeProcess(pi.hProcess, &exitcode);
+/*
+ The method sets the crash flag and wakes all waiters on
+ COND_instance_stopped and COND_guardian
- // Close process and thread handles.
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
+ SYNOPSYS
+ set_crash_flag_n_wake_all()
- return exitcode;
-}
-#endif
+ DESCRIPTION
+ The method is called when an instance is crashed or terminated.
+ In the former case it might indicate that guardian probably should
+ restart it.
+ RETURN
+ Function returns no value
+*/
-void Instance::fork_and_monitor()
+void Instance::set_crash_flag_n_wake_all()
{
- log_info("starting instance %s", options.instance_name);
-
- if (launch_and_wait())
- return; /* error is logged */
-
/* set instance state to crashed */
pthread_mutex_lock(&LOCK_instance);
crashed= 1;
@@ -230,11 +369,10 @@ void Instance::fork_and_monitor()
pthread_cond_signal(&COND_instance_stopped);
/* wake guardian */
pthread_cond_signal(&instance_map->guardian->COND_guardian);
- /* thread exits */
- return;
}
+
Instance::Instance(): crashed(0)
{
pthread_mutex_init(&LOCK_instance, 0);
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index 0ff5ecc179e..cbcfee0c7ef 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -41,7 +41,8 @@ public:
/* send a signal to the instance */
void kill_instance(int signo);
int is_crashed();
- void fork_and_monitor();
+ void set_crash_flag_n_wake_all();
+ Instance_map *get_map();
public:
enum { DEFAULT_SHUTDOWN_DELAY= 35 };
@@ -63,7 +64,6 @@ private:
Instance_map *instance_map;
void remove_pid();
- int launch_and_wait();
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
index 0ae364e5b2d..998bf470c8d 100644
--- a/server-tools/instance-manager/instance_options.cc
+++ b/server-tools/instance-manager/instance_options.cc
@@ -130,6 +130,8 @@ int Instance_options::fill_instance_version()
version_option, sizeof(version_option)))
goto err;
+ bzero(result, MAX_VERSION_STRING_LENGTH);
+
rc= parse_output_and_get_value(cmd.buffer, mysqld_path,
result, MAX_VERSION_STRING_LENGTH,
GET_LINE);
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index de80878e283..a1420a639cb 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -79,6 +79,7 @@ int HandleServiceOptions(Options options);
int main(int argc, char *argv[])
{
+ int return_value= 1;
init_environment(argv[0]);
Options options;
struct passwd *user_info;
@@ -90,10 +91,7 @@ int main(int argc, char *argv[])
if ((user_info= check_user(options.user)))
{
if (set_user(options.user, user_info))
- {
- options.cleanup();
goto err;
- }
}
if (options.run_as_service)
@@ -105,17 +103,18 @@ int main(int argc, char *argv[])
}
#else
#ifdef NDEBUG
- return HandleServiceOptions(options);
+ return_value= HandleServiceOptions(options);
+ goto err; /* this is not always an error but we reuse the label */
#endif
#endif
manager(options);
- options.cleanup();
- my_end(0);
- return 0;
+ return_value= 0;
+
err:
+ options.cleanup();
my_end(0);
- return 1;
+ return return_value;
}
/******************* Auxilary functions implementation **********************/
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
index a9d31457d98..6fd11471fc6 100644
--- a/server-tools/instance-manager/options.cc
+++ b/server-tools/instance-manager/options.cc
@@ -30,18 +30,20 @@
#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
-const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
-const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
#ifdef __WIN__
-char windows_config_file[FN_REFLEN];
-
char Options::install_as_service;
char Options::remove_service;
+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 */
-#endif
+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);
+#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);
@@ -51,7 +53,7 @@ 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 */
-char **Options::saved_argv;
+char **Options::saved_argv= NULL;
/*
List of options, accepted by the instance manager.
@@ -262,30 +264,8 @@ int Options::load(int argc, char **argv)
}
#ifdef __WIN__
- setup_windows_defaults(*argv);
-
- /*
- On Windows, there are two possibilities. Either we are given
- a defaults file on the command line or we use the my.ini file
- that is in our app dir
- */
- if (Options::config_file == NULL)
- {
- char *filename;
- static const char default_win_config_file_name[]= "\\my.ini";
-
- if (!GetModuleFileName(NULL, windows_config_file,
- sizeof(windows_config_file)))
- goto err;
-
- filename= strrchr(windows_config_file, "\\");
- /*
- Don't check for the overflow as strlen("\\my.ini") is less
- then strlen("mysqlmanager") (the binary name)
- */
- strcpy(filename, default_win_config_file_name);
- Options::config_file= windows_config_file;
- }
+ if (setup_windows_defaults())
+ goto err;
#endif
/* config-file options are prepended to command-line ones */
@@ -305,33 +285,32 @@ err:
void Options::cleanup()
{
/* free_defaults returns nothing */
- free_defaults(Options::saved_argv);
-#ifdef __WIN__
- free((char*)default_password_file_name);
-#endif
+ if (Options::saved_argv != NULL)
+ free_defaults(Options::saved_argv);
}
#ifdef __WIN__
-char* change_extension(const char *src, const char *newext)
+int Options::setup_windows_defaults()
{
- char *dot= (char*)strrchr(src, '.');
- if (!dot) return (char*)src;
-
- int newlen= dot-src+strlen(newext)+1;
- char *temp= (char*)malloc(newlen);
- bzero(temp, newlen);
- strncpy(temp, src, dot-src+1);
- strcat(temp, newext);
- return temp;
-}
-
-void Options::setup_windows_defaults(const char *progname)
-{
- Options::password_file_name= default_password_file_name=
- change_extension(progname, "passwd");
- Options::log_file_name= default_log_file_name=
- change_extension(progname, "log");
+ 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)))
+ return 1;
+ filename= strstr(default_log_file_name, ".exe");
+ strcpy(filename, ".log");
+
+ if (!GetModuleFileName(NULL, windows_config_file,
+ sizeof(windows_config_file)))
+ return 1;
+ char *slash= strrchr(windows_config_file, '\\');
+ strcpy(slash, "\\my.ini");
+ return 0;
}
#endif
diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h
index 537316fedfc..5cc14e7ee7f 100644
--- a/server-tools/instance-manager/options.h
+++ b/server-tools/instance-manager/options.h
@@ -52,7 +52,7 @@ struct Options
int load(int argc, char **argv);
void cleanup();
#ifdef __WIN__
- void setup_windows_defaults(const char *progname);
+ int setup_windows_defaults(const char *progname);
#endif
};
diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc
index 4b46d091c3f..cd1be805b6b 100644
--- a/server-tools/instance-manager/protocol.cc
+++ b/server-tools/instance-manager/protocol.cc
@@ -203,7 +203,7 @@ int send_fields(struct st_net *net, LIST *fields)
position+= 12;
if (my_net_write(net, send_buff.buffer, (uint) position+1))
goto err;
- tmp= rest(tmp);
+ tmp= list_rest(tmp);
}
if (my_net_write(net, eof_buff, 1))
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index 1498f2fa947..4e47127bba1 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -25,12 +25,6 @@
#include "log.h"
-#ifdef __WIN__
-#define NEWLINE_LEN 2
-#else
-#define NEWLINE_LEN 1
-#endif
-
struct User
{
char user[USERNAME_LENGTH + 1];
@@ -43,6 +37,7 @@ struct User
int User::init(const char *line)
{
const char *name_begin, *name_end, *password;
+ int line_ending_len= 1;
if (line[0] == '\'' || line[0] == '"')
{
@@ -64,8 +59,14 @@ int User::init(const char *line)
if (user_length > USERNAME_LENGTH)
goto err;
- /* assume that newline characater is present */
- if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + NEWLINE_LEN)
+ /*
+ 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) != SCRAMBLED_PASSWORD_CHAR_LENGTH + line_ending_len)
goto err;
memcpy(user, name_begin, user_length);
diff --git a/sql-common/client.c b/sql-common/client.c
index 4ec919553c6..993978f132f 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -713,8 +713,9 @@ void free_old_query(MYSQL *mysql)
if (mysql->fields)
free_root(&mysql->field_alloc,MYF(0));
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
- mysql->fields=0;
- mysql->field_count=0; /* For API */
+ mysql->fields= 0;
+ mysql->field_count= 0; /* For API */
+ mysql->info= 0;
DBUG_VOID_RETURN;
}
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 95ac779e0cd..72809ee9b4b 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -197,7 +197,9 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
If length= 8 or >= 14 then year is of format YYYY.
(YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
*/
- for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++)
+ for (pos=str;
+ pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T');
+ pos++)
;
digits= (uint) (pos-str);
@@ -263,7 +265,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
const char *start= str;
ulong tmp_value= (uint) (uchar) (*str++ - '0');
while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
- --field_length)
+ (!is_internal_format || --field_length))
{
tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
str++;
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index a7e193b9730..dfc2fa7a260 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -67,7 +67,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include <mysql_priv.h>
+#include "../mysql_priv.h"
#ifdef HAVE_EXAMPLE_DB
#include "ha_example.h"
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index fc7347ef9af..40f3ff85c58 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -640,7 +640,10 @@ void field_conv(Field *to,Field *from)
(!(to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
to->type() != FIELD_TYPE_DATE &&
- to->type() != FIELD_TYPE_DATETIME))
+ to->type() != FIELD_TYPE_DATETIME) &&
+ (from->real_type() != MYSQL_TYPE_VARCHAR ||
+ ((Field_varstring*)from)->length_bytes ==
+ ((Field_varstring*)to)->length_bytes))
{ // Identical fields
#ifdef HAVE_purify
/* This may happen if one does 'UPDATE ... SET x=x' */
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index d69f9d74a01..9a0e0ed1488 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -958,8 +958,6 @@ int ha_berkeley::write_row(byte * record)
{
DB_TXN *sub_trans = transaction;
/* Don't use sub transactions in temporary tables */
- ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
- table->in_use->options : 0);
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys(0);
@@ -1070,7 +1068,7 @@ int ha_berkeley::key_cmp(uint keynr, const byte * old_row,
int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
const byte * old_row, DBT *old_key,
const byte * new_row, DBT *new_key,
- ulong thd_options, bool local_using_ignore)
+ bool local_using_ignore)
{
DBT row;
int error;
@@ -1119,8 +1117,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys,
uint primary_key,
const byte *old_row, DBT *old_key,
- const byte *new_row, DBT *new_key,
- ulong thd_options)
+ const byte *new_row, DBT *new_key)
{
int error;
DBT tmp_key;
@@ -1130,7 +1127,7 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys,
/* Restore the old primary key, and the old row, but don't ignore
duplicate key failure */
if ((error=update_primary_key(trans, TRUE, new_row, new_key,
- old_row, old_key, thd_options, FALSE)))
+ old_row, old_key, FALSE)))
goto err; /* purecov: inspected */
/* Remove the new key, and put back the old key
@@ -1167,8 +1164,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DBT prim_key, key, old_prim_key;
int error;
DB_TXN *sub_trans;
- ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
- table->in_use->options : 0);
bool primary_key_changed;
DBUG_ENTER("update_row");
LINT_INIT(error);
@@ -1204,7 +1199,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
if (!(error=update_primary_key(sub_trans, primary_key_changed,
old_row, &old_prim_key,
new_row, &prim_key,
- thd_options, using_ignore)))
+ using_ignore)))
{
// Update all other keys
for (uint keynr=0 ; keynr < table->s->keys ; keynr++)
@@ -1239,8 +1234,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
int new_error = 0;
if (!changed_keys.is_clear_all())
new_error=restore_keys(transaction, &changed_keys, primary_key,
- old_row, &old_prim_key, new_row, &prim_key,
- thd_options);
+ old_row, &old_prim_key, new_row, &prim_key);
if (new_error)
{
/* This shouldn't happen */
@@ -1342,8 +1336,6 @@ int ha_berkeley::delete_row(const byte * record)
int error;
DBT row, prim_key;
key_map keys= table->s->keys_in_use;
- ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
- table->in_use->options : 0);
DBUG_ENTER("delete_row");
statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
@@ -2150,7 +2142,7 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
end_pos=end_range.less+end_range.equal;
rows=(end_pos-start_pos)*records;
DBUG_PRINT("exit",("rows: %g",rows));
- DBUG_RETURN(rows <= 1.0 ? (ha_rows) 1 : (ha_rows) rows);
+ DBUG_RETURN((ha_rows)(rows <= 1.0 ? 1 : rows));
}
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index ee8f4b80049..aab76accefa 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -74,13 +74,12 @@ class ha_berkeley: public handler
DBT *prim_key, key_map *keys);
int restore_keys(DB_TXN *trans, key_map *changed_keys, uint primary_key,
const byte *old_row, DBT *old_key,
- const byte *new_row, DBT *new_key,
- ulong thd_options);
+ const byte *new_row, DBT *new_key);
int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
int update_primary_key(DB_TXN *trans, bool primary_key_changed,
const byte * old_row, DBT *old_key,
const byte * new_row, DBT *prim_key,
- ulong thd_options, bool local_using_ignore);
+ bool local_using_ignore);
int read_row(int error, char *buf, uint keynr, DBT *row, DBT *key, bool);
DBT *get_pos(DBT *to, byte *pos);
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index a57343fb543..24097460a24 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -43,6 +43,8 @@ public:
return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? "BTREE" :
"HASH");
}
+ /* 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
{
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 93d830d9fb1..df58a722e9a 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -48,6 +48,10 @@ have disables the InnoDB inlining in this file. */
pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */
prepare_commit_mutex; /* to force correct commit order in
binlog */
+ulong commit_threads= 0;
+pthread_mutex_t commit_threads_m;
+pthread_cond_t commit_cond;
+pthread_mutex_t commit_cond_m;
bool innodb_inited= 0;
/*-----------------------------------------------------------------*/
@@ -550,19 +554,20 @@ innobase_mysql_end_print_arbitrary_thd(void)
}
/*****************************************************************
-Prints info of a THD object (== user session thread) to the
-standard output. NOTE that /mysql/innobase/trx/trx0trx.c must contain
-the prototype for this function! */
+Prints info of a THD object (== user session thread) to the given file.
+NOTE that /mysql/innobase/trx/trx0trx.c must contain the prototype for
+this function! */
extern "C"
void
innobase_mysql_print_thd(
/*=====================*/
- FILE* f, /* in: output stream */
- void* input_thd)/* in: pointer to a MySQL THD object */
+ FILE* f, /* in: output stream */
+ void* input_thd, /* in: pointer to a MySQL THD object */
+ uint max_query_len) /* in: max query length to print, or 0 to
+ use the default max length */
{
const THD* thd;
const char* s;
- char buf[301];
thd = (const THD*) input_thd;
@@ -589,25 +594,47 @@ innobase_mysql_print_thd(
}
if ((s = thd->query)) {
- /* determine the length of the query string */
- uint32 i, len;
+ /* 3100 is chosen because currently 3000 is the maximum
+ max_query_len we ever give this. */
+ char buf[3100];
+ uint len;
+
+ /* If buf is too small, we dynamically allocate storage
+ in this. */
+ char* dyn_str = NULL;
+
+ /* Points to buf or dyn_str. */
+ char* str = buf;
- len = thd->query_length;
-
- if (len > 300) {
- len = 300; /* ADDITIONAL SAFETY: print at most
- 300 chars to reduce the probability of
- a seg fault if there is a race in
- thd->query_length in MySQL; after
- May 14, 2004 probably no race any more,
- but better be safe */
+ if (max_query_len == 0)
+ {
+ /* ADDITIONAL SAFETY: the default is to print at
+ most 300 chars to reduce the probability of a
+ seg fault if there is a race in
+ thd->query_length in MySQL; after May 14, 2004
+ probably no race any more, but better be
+ safe */
+ max_query_len = 300;
+ }
+
+ len = min(thd->query_length, max_query_len);
+
+ if (len > (sizeof(buf) - 1))
+ {
+ dyn_str = my_malloc(len + 1, MYF(0));
+ str = dyn_str;
}
- /* Use strmake to reduce the timeframe
- for a race, compared to fwrite() */
- i= (uint) (strmake(buf, s, len) - buf);
+ /* Use strmake to reduce the timeframe for a race,
+ compared to fwrite() */
+ len = (uint) (strmake(str, s, len) - str);
putc('\n', f);
- fwrite(buf, 1, i, f);
+ fwrite(str, 1, len, f);
+
+ if (dyn_str)
+ {
+ my_free(dyn_str, MYF(0));
+ }
}
putc('\n', f);
@@ -948,9 +975,9 @@ innobase_query_caching_of_table_permitted(
trx = check_trx_exists(thd);
if (trx->has_search_latch) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: the calling thread is holding the adaptive search\n"
-"InnoDB: latch though calling innobase_query_caching_of_table_permitted\n");
+ sql_print_error("The calling thread is holding the adaptive "
+ "search, latch though calling "
+ "innobase_query_caching_of_table_permitted.");
}
innobase_release_stat_resources(trx);
@@ -1266,9 +1293,8 @@ innobase_init(void)
&srv_log_group_home_dirs);
if (ret == FALSE || innobase_mirrored_log_groups != 1) {
- fprintf(stderr,
- "InnoDB: syntax error in innodb_log_group_home_dir\n"
- "InnoDB: or a wrong number of mirrored log groups\n");
+ sql_print_error("syntax error in innodb_log_group_home_dir, or a "
+ "wrong number of mirrored log groups");
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
@@ -1367,6 +1393,9 @@ innobase_init(void)
(hash_get_key) innobase_get_key, 0, 0);
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&commit_cond, NULL);
innodb_inited= 1;
/* If this is a replication slave and we needed to do a crash recovery,
@@ -1416,6 +1445,9 @@ innobase_end(void)
MYF(MY_ALLOW_ZERO_PTR));
pthread_mutex_destroy(&innobase_share_mutex);
pthread_mutex_destroy(&prepare_commit_mutex);
+ pthread_mutex_destroy(&commit_threads_m);
+ pthread_mutex_destroy(&commit_cond_m);
+ pthread_cond_destroy(&commit_cond);
}
DBUG_RETURN(err);
@@ -1542,8 +1574,10 @@ innobase_commit(
reserve the kernel mutex, we have to release the search system latch
first to obey the latching order. */
- innobase_release_stat_resources(trx);
-
+ if (trx->has_search_latch) {
+ trx_search_latch_release_if_reserved(trx);
+ }
+
/* The flag trx->active_trans is set to 1 in
1. ::external_lock(),
@@ -1562,11 +1596,9 @@ innobase_commit(
if (trx->active_trans == 0
&& trx->conc_state != TRX_NOT_STARTED) {
- fprintf(stderr,
-"InnoDB: Error: trx->active_trans == 0\n"
-"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
+ sql_print_error("trx->active_trans == 0, but trx->conc_state != "
+ "TRX_NOT_STARTED");
}
-
if (all
|| (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
@@ -1575,18 +1607,43 @@ innobase_commit(
/* We need current binlog position for ibbackup to work.
Note, the position is current because of prepare_commit_mutex */
+retry:
+ if (srv_commit_concurrency > 0)
+ {
+ pthread_mutex_lock(&commit_cond_m);
+ commit_threads++;
+ if (commit_threads > srv_commit_concurrency)
+ {
+ commit_threads--;
+ pthread_cond_wait(&commit_cond, &commit_cond_m);
+ pthread_mutex_unlock(&commit_cond_m);
+ goto retry;
+ }
+ else
+ pthread_mutex_unlock(&commit_cond_m);
+ }
+
trx->mysql_log_file_name = mysql_bin_log.get_log_fname();
trx->mysql_log_offset =
(ib_longlong)mysql_bin_log.get_log_file()->pos_in_file;
innobase_commit_low(trx);
+ if (srv_commit_concurrency > 0)
+ {
+ pthread_mutex_lock(&commit_cond_m);
+ commit_threads--;
+ pthread_cond_signal(&commit_cond);
+ pthread_mutex_unlock(&commit_cond_m);
+ }
+
if (trx->active_trans == 2) {
pthread_mutex_unlock(&prepare_commit_mutex);
}
+
trx->active_trans = 0;
-
+
} else {
/* We just mark the SQL statement ended and do not do a
transaction commit */
@@ -1606,7 +1663,11 @@ innobase_commit(
/* Tell the InnoDB server that there might be work for utility
threads: */
+ if (trx->declared_to_be_inside_innodb) {
+ /* Release our possible ticket in the FIFO */
+ srv_conc_force_exit_innodb(trx);
+ }
srv_active_wake_master_thread();
DBUG_RETURN(0);
@@ -1813,21 +1874,23 @@ try_again:
if (ret != 0) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: MySQL synchronous replication\n"
-"InnoDB: was not able to send the binlog to the slave within the\n"
-"InnoDB: timeout %lu. We assume that the slave has become inaccessible,\n"
-"InnoDB: and switch off synchronous replication until the communication.\n"
-"InnoDB: to the slave works again.\n",
- thd->variables.sync_replication_timeout);
- fprintf(stderr,
-"InnoDB: MySQL synchronous replication has sent binlog\n"
-"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name,
- (ulong)innobase_repl_pos);
- fprintf(stderr,
-"InnoDB: This transaction needs it to be sent up to\n"
-"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name,
- (ulong)trx->repl_wait_binlog_pos);
+ sql_print_error("MySQL synchronous replication was "
+ "not able to send the binlog to the "
+ "slave within the timeout %lu. We "
+ "assume that the slave has become "
+ "inaccessible, and switch off "
+ "synchronous replication until the "
+ "communication to the slave works "
+ "again. MySQL synchronous replication "
+ "has sent binlog to the slave up to "
+ "file %s, position %lu. This "
+ "transaction needs it to be sent up "
+ "to file %s, position %lu.",
+ thd->variables.sync_replication_timeout,
+ innobase_repl_file_name,
+ (ulong) innobase_repl_pos,
+ trx->repl_wait_binlog_name,
+ (ulong) trx->repl_wait_binlog_pos);
innobase_repl_state = 0;
@@ -1878,9 +1941,9 @@ innobase_repl_report_sent_binlog(
if (innobase_repl_state == 0) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Switching MySQL synchronous replication on again at\n"
-"InnoDB: binlog file %s, position %lu\n", log_file_name, (ulong)end_offset);
+ sql_print_warning("Switching MySQL synchronous replication on "
+ "again at binlog file %s, position %lu",
+ log_file_name, (ulong) end_offset);
innobase_repl_state = 1;
}
@@ -1897,14 +1960,14 @@ innobase_repl_report_sent_binlog(
|| (cmp == 0 && end_offset < innobase_repl_pos)) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: MySQL synchronous replication has sent binlog\n"
-"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name,
- (ulong)innobase_repl_pos);
- fprintf(stderr,
-"InnoDB: but now MySQL reports that it sent the binlog only up to\n"
-"InnoDB: file %s, position %lu\n", log_file_name, (ulong)end_offset);
-
+ sql_print_error("MySQL synchronous replication has "
+ "sent binlog to the slave up to file "
+ "%s, position %lu, but now MySQL "
+ "reports that it sent the binlog only "
+ "up to file %s, position %lu",
+ innobase_repl_file_name,
+ (ulong) innobase_repl_pos,
+ log_file_name, (ulong) end_offset);
}
}
@@ -2146,16 +2209,21 @@ innobase_close_connection(
ut_a(trx);
- if (trx->conc_state != TRX_NOT_STARTED) {
- ut_print_timestamp(stderr);
-
- fprintf(stderr,
-" InnoDB: Warning: MySQL is closing a connection"
-"InnoDB: that has an active InnoDB transaction. We roll back that\n"
-"InnoDB: transaction. %lu row modifications to roll back.\n",
- (ulong)trx->undo_no.low);
+ if (trx->active_trans == 0
+ && trx->conc_state != TRX_NOT_STARTED) {
+
+ sql_print_error("trx->active_trans == 0, but trx->conc_state != "
+ "TRX_NOT_STARTED");
}
+
+ if (trx->conc_state != TRX_NOT_STARTED &&
+ global_system_variables.log_warnings)
+ sql_print_warning("MySQL is closing a connection that has an active "
+ "InnoDB transaction. %lu row modifications will "
+ "roll back.",
+ (ulong)trx->undo_no.low);
+
innobase_rollback_trx(trx);
trx_free_for_mysql(trx);
@@ -2306,15 +2374,17 @@ ha_innobase::open(
norm_name, NULL);
if (NULL == ib_table) {
ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB error:\n"
-"Cannot find table %s from the internal data dictionary\n"
-"of InnoDB though the .frm file for the table exists. Maybe you\n"
-"have deleted and recreated InnoDB data files but have forgotten\n"
-"to delete the corresponding .frm files of InnoDB tables, or you\n"
-"have moved .frm files to another database?\n"
-"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"how you can resolve the problem.\n",
- norm_name);
+ sql_print_error("Cannot find table %s from the internal data "
+ "dictionary\nof InnoDB though the .frm file "
+ "for the table exists. Maybe you\nhave "
+ "deleted and recreated InnoDB data files but "
+ "have forgotten\nto delete the corresponding "
+ ".frm files of InnoDB tables, or you\n"
+ "have moved .frm files to another database?\n"
+ "Look from section 15.1 of "
+ "http://www.innodb.com/ibman.html\n"
+ "how you can resolve the problem.\n",
+ norm_name);
free_share(share);
my_free((char*) upd_buff, MYF(0));
my_errno = ENOENT;
@@ -2324,14 +2394,15 @@ ha_innobase::open(
if (ib_table->ibd_file_missing && !thd->tablespace_op) {
ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB error:\n"
-"MySQL is trying to open a table handle but the .ibd file for\n"
-"table %s does not exist.\n"
-"Have you deleted the .ibd file from the database directory under\n"
-"the MySQL datadir, or have you used DISCARD TABLESPACE?\n"
-"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"how you can resolve the problem.\n",
- norm_name);
+ sql_print_error("MySQL is trying to open a table handle but "
+ "the .ibd file for\ntable %s does not exist.\n"
+ "Have you deleted the .ibd file from the "
+ "database directory under\nthe MySQL datadir, "
+ "or have you used DISCARD TABLESPACE?\n"
+ "Look from section 15.1 of "
+ "http://www.innodb.com/ibman.html\n"
+ "how you can resolve the problem.\n",
+ norm_name);
free_share(share);
my_free((char*) upd_buff, MYF(0));
my_errno = ENOENT;
@@ -2357,9 +2428,8 @@ ha_innobase::open(
if (!row_table_got_default_clust_index(ib_table)) {
if (primary_key >= MAX_KEY) {
- fprintf(stderr,
- "InnoDB: Error: table %s has a primary key in InnoDB\n"
- "InnoDB: data dictionary, but not in MySQL!\n", name);
+ sql_print_error("Table %s has a primary key in InnoDB data "
+ "dictionary, but not in MySQL!", name);
}
((row_prebuilt_t*)innobase_prebuilt)
@@ -2373,16 +2443,15 @@ ha_innobase::open(
ref_length = table->key_info[primary_key].key_length;
} else {
if (primary_key != MAX_KEY) {
- fprintf(stderr,
- "InnoDB: Error: table %s has no primary key in InnoDB\n"
- "InnoDB: data dictionary, but has one in MySQL!\n"
- "InnoDB: If you created the table with a MySQL\n"
- "InnoDB: version < 3.23.54 and did not define a primary\n"
- "InnoDB: key, but defined a unique key with all non-NULL\n"
- "InnoDB: columns, then MySQL internally treats that key\n"
- "InnoDB: as the primary key. You can fix this error by\n"
- "InnoDB: dump + DROP + CREATE + reimport of the table.\n",
- name);
+ sql_print_error("Table %s has no primary key in InnoDB data "
+ "dictionary, but has one in MySQL! If you "
+ "created the table with a MySQL version < "
+ "3.23.54 and did not define a primary key, "
+ "but defined a unique key with all non-NULL "
+ "columns, then MySQL internally treats that "
+ "key as the primary key. You can fix this "
+ "error by dump + DROP + CREATE + reimport "
+ "of the table.", name);
}
((row_prebuilt_t*)innobase_prebuilt)
@@ -2399,10 +2468,9 @@ ha_innobase::open(
and it will never be updated anyway. */
if (key_used_on_scan != MAX_KEY) {
- fprintf(stderr,
-"InnoDB: Warning: table %s key_used_on_scan is %lu even though there is no\n"
-"InnoDB: primary key inside InnoDB.\n",
- name, (ulong)key_used_on_scan);
+ sql_print_warning("Table %s key_used_on_scan is %lu even "
+ "though there is no primary key inside "
+ "InnoDB.", name, (ulong) key_used_on_scan);
}
}
@@ -2557,9 +2625,10 @@ innobase_mysql_cmp(
charset = get_charset(charset_number, MYF(MY_WME));
if (charset == NULL) {
- fprintf(stderr,
-"InnoDB: fatal error: InnoDB needs charset %lu for doing a comparison,\n"
-"InnoDB: but MySQL cannot find that charset.\n", (ulong)charset_number);
+ sql_print_error("InnoDB needs charset %lu for doing "
+ "a comparison, but MySQL cannot "
+ "find that charset.",
+ (ulong) charset_number);
ut_a(0);
}
}
@@ -3126,11 +3195,11 @@ ha_innobase::write_row(
if (prebuilt->trx !=
(trx_t*) current_thd->ha_data[innobase_hton.slot]) {
- fprintf(stderr,
-"InnoDB: Error: the transaction object for the table handle is at\n"
-"InnoDB: %p, but for the current thread it is at %p\n",
- prebuilt->trx,
- (trx_t*) current_thd->ha_data[innobase_hton.slot]);
+ sql_print_error("The transaction object for the table handle is at "
+ "%p, but for the current thread it is at %p",
+ prebuilt->trx,
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
+
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
fputs("\n"
@@ -3617,9 +3686,9 @@ ha_innobase::unlock_row(void)
if (last_query_id != user_thd->query_id) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: last_query_id is %lu != user_thd_query_id is %lu\n",
- (ulong)last_query_id, (ulong)user_thd->query_id);
+ sql_print_error("last_query_id is %lu != user_thd_query_id is "
+ "%lu", (ulong) last_query_id,
+ (ulong) user_thd->query_id);
mem_analyze_corruption((byte *) prebuilt->trx);
ut_error;
}
@@ -3912,9 +3981,10 @@ ha_innobase::change_active_index(
}
if (!prebuilt->index) {
- sql_print_error(
-"Innodb could not find key n:o %u with name %s from dict cache for table %s",
- keynr, key ? key->name : "NULL", prebuilt->table->name);
+ sql_print_error("Innodb could not find key n:o %u with name %s "
+ "from dict cache for table %s",
+ keynr, key ? key->name : "NULL",
+ prebuilt->table->name);
DBUG_RETURN(1);
}
@@ -4280,9 +4350,8 @@ ha_innobase::position(
table. */
if (len != ref_length) {
- fprintf(stderr,
- "InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n",
- (ulong)len, (ulong)ref_length);
+ sql_print_error("Stored ref len is %lu, but table ref len is %lu",
+ (ulong) len, (ulong) ref_length);
}
}
@@ -4487,11 +4556,13 @@ create_index(
|| col_type == DATA_FLOAT
|| col_type == DATA_DOUBLE
|| col_type == DATA_DECIMAL) {
- fprintf(stderr,
-"InnoDB: error: MySQL is trying to create a column prefix index field\n"
-"InnoDB: on an inappropriate data type. Table name %s, column name %s.\n",
- table_name, key_part->field->field_name);
-
+ sql_print_error("MySQL is trying to create a column "
+ "prefix index field, on an "
+ "inappropriate data type. Table "
+ "name %s, column name %s.",
+ table_name,
+ key_part->field->field_name);
+
prefix_len = 0;
}
} else {
@@ -5282,6 +5353,7 @@ ha_innobase::info(
dict_table_t* ib_table;
dict_index_t* index;
ha_rows rec_per_key;
+ ib_longlong n_rows;
ulong j;
ulong i;
char path[FN_REFLEN];
@@ -5346,7 +5418,30 @@ ha_innobase::info(
}
if (flag & HA_STATUS_VARIABLE) {
- records = (ha_rows)ib_table->stat_n_rows;
+ n_rows = ib_table->stat_n_rows;
+
+ /* Because we do not protect stat_n_rows by any mutex in a
+ delete, it is theoretically possible that the value can be
+ smaller than zero! TODO: fix this race.
+
+ The MySQL optimizer seems to assume in a left join that n_rows
+ is an accurate estimate if it is zero. Of course, it is not,
+ since we do not have any locks on the rows yet at this phase.
+ Since SHOW TABLE STATUS seems to call this function with the
+ HA_STATUS_TIME flag set, while the left join optizer does not
+ set that flag, we add one to a zero value if the flag is not
+ set. That way SHOW TABLE STATUS will show the best estimate,
+ while the optimizer never sees the table empty. */
+
+ if (n_rows < 0) {
+ n_rows = 0;
+ }
+
+ if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
+ n_rows++;
+ }
+
+ records = (ha_rows)n_rows;
deleted = 0;
data_file_length = ((ulonglong)
ib_table->stat_clustered_index_size)
@@ -5374,12 +5469,14 @@ ha_innobase::info(
for (i = 0; i < table->s->keys; i++) {
if (index == NULL) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: table %s contains less indexes inside InnoDB\n"
-"InnoDB: than are defined in the MySQL .frm file. Have you mixed up\n"
-"InnoDB: .frm files from different installations? See section\n"
-"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n",
- ib_table->name);
+ sql_print_error("Table %s contains less "
+ "indexes inside InnoDB than "
+ "are defined in the MySQL "
+ ".frm file. Have you mixed up "
+ ".frm files from different "
+ "installations? See section "
+ "15.1 at http://www.innodb.com/ibman.html",
+ ib_table->name);
break;
}
@@ -5387,15 +5484,21 @@ ha_innobase::info(
if (j + 1 > index->n_uniq) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: index %s of %s has %lu columns unique inside InnoDB\n"
-"InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed up\n"
-"InnoDB: .frm files from different installations? See section\n"
-"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n",
- index->name,
- ib_table->name,
- (unsigned long) index->n_uniq,
- j + 1);
+ sql_print_error("Index %s of %s has "
+ "%lu columns unique "
+ "inside InnoDB, but "
+ "MySQL is asking "
+ "statistics for %lu "
+ "columns. Have you "
+ "mixed up .frm files "
+ "from different "
+ "installations? See "
+ "section 15.1 at "
+ "http://www.innodb.com/ibman.html",
+ index->name,
+ ib_table->name,
+ (unsigned long)
+ index->n_uniq, j + 1);
break;
}
@@ -5943,9 +6046,9 @@ ha_innobase::start_stmt(
if (prebuilt->stored_select_lock_type != LOCK_S
&& prebuilt->stored_select_lock_type != LOCK_X) {
- fprintf(stderr,
-"InnoDB: Error: stored_select_lock_type is %lu inside ::start_stmt()!\n",
- prebuilt->stored_select_lock_type);
+ sql_print_error("stored_select_lock_type is %lu inside "
+ "::start_stmt()!",
+ prebuilt->stored_select_lock_type);
/* Set the value to LOCK_X: this is just fault
tolerance, we do not know what the correct value
@@ -6721,9 +6824,8 @@ ha_innobase::innobase_read_and_init_auto_inc(
error = 0;
} else {
/* This should not happen in a consistent read */
- fprintf(stderr,
-"InnoDB: Error: consistent read of auto-inc column returned %lu\n",
- (ulong)error);
+ sql_print_error("Consistent read of auto-inc column "
+ "returned %lu", (ulong) error);
auto_inc = -1;
goto func_exit;
@@ -6780,9 +6882,8 @@ ha_innobase::get_auto_increment()
initialized. */
ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: error %lu in ::get_auto_increment()\n",
- (ulong)error);
+ sql_print_error("Error %lu in ::get_auto_increment()",
+ (ulong) error);
return(~(ulonglong) 0);
}
@@ -6857,8 +6958,8 @@ ha_innobase::cmp_ref(
return(result);
}
- ref1 += key_part->length;
- ref2 += key_part->length;
+ ref1 += key_part->store_length;
+ ref2 += key_part->store_length;
}
return(0);
@@ -7039,7 +7140,7 @@ innobase_xa_prepare(
return(0);
}
- trx->xid=thd->transaction.xid;
+ trx->xid=thd->transaction.xid_state.xid;
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
@@ -7049,9 +7150,8 @@ innobase_xa_prepare(
if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
- fprintf(stderr,
-"InnoDB: Error: trx->active_trans == 0\n"
-"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
+ sql_print_error("trx->active_trans == 0, but trx->conc_state != "
+ "TRX_NOT_STARTED");
}
if (all
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index b0a463798d9..3ff925e30de 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -244,6 +244,7 @@ extern ulong srv_n_spin_wait_rounds;
extern ulong srv_n_free_tickets_to_enter;
extern ulong srv_thread_sleep_delay;
extern ulong srv_thread_concurrency;
+extern ulong srv_commit_concurrency;
}
extern TYPELIB innobase_lock_typelib;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 959b8d100bb..9fb1a25cea7 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -2921,7 +2921,16 @@ void ha_ndbcluster::info(uint flag)
errkey= m_dupkey;
}
if (flag & HA_STATUS_AUTO)
+ {
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
+ if (m_table)
+ {
+ Ndb *ndb= get_ndb();
+
+ auto_increment_value=
+ ndb->readAutoIncrementValue((const NDBTAB *) m_table);
+ }
+ }
DBUG_VOID_RETURN;
}
@@ -3243,7 +3252,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("info", ("Table schema version: %d",
tab->getObjectVersion()));
// Check if thread has stale local cache
- if (tab->getObjectStatus() == NdbDictionary::Object::Invalid)
+ // New transaction must not use old tables... (trans != 0)
+ // Running might...
+ if ((trans && tab->getObjectStatus() != NdbDictionary::Object::Retrieved)
+ || tab->getObjectStatus() == NdbDictionary::Object::Invalid)
{
invalidate_dictionary_cache(FALSE);
if (!(tab= dict->getTable(m_tabname, &tab_info)))
@@ -6947,6 +6959,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
break;
Ndb_item *a= cond->next->ndb_item;
Ndb_item *b, *field, *value= NULL;
+ LINT_INIT(field);
+
switch (cond->ndb_item->argument_count()) {
case 1:
field=
diff --git a/sql/handler.cc b/sql/handler.cc
index 3c64d33c371..451615bead1 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -609,8 +609,8 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
trans->ht[trans->nht++]=ht_arg;
DBUG_ASSERT(*ht == ht_arg);
trans->no_2pc|=(ht_arg->prepare==0);
- if (thd->transaction.xid.is_null())
- thd->transaction.xid.set(thd->query_id);
+ if (thd->transaction.xid_state.xid.is_null())
+ thd->transaction.xid_state.xid.set(thd->query_id);
DBUG_VOID_RETURN;
}
@@ -657,7 +657,7 @@ int ha_commit_trans(THD *thd, bool all)
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
bool is_real_trans= all || thd->transaction.all.nht == 0;
handlerton **ht= trans->ht;
- my_xid xid= thd->transaction.xid.get_my_xid();
+ my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
DBUG_ENTER("ha_commit_trans");
if (thd->in_sub_stmt)
@@ -757,7 +757,7 @@ int ha_commit_one_phase(THD *thd, bool all)
trans->nht=0;
trans->no_2pc=0;
if (is_real_trans)
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
if (all)
{
#ifdef HAVE_QUERY_CACHE
@@ -813,7 +813,7 @@ int ha_rollback_trans(THD *thd, bool all)
trans->nht=0;
trans->no_2pc=0;
if (is_real_trans)
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
if (all)
{
thd->variables.tx_isolation=thd->session_tx_isolation;
@@ -1007,6 +1007,7 @@ int ha_recover(HASH *commit_list)
char buf[XIDDATASIZE*4+6]; // see xid_to_str
sql_print_information("ignore xid %s", xid_to_str(buf, list+i));
#endif
+ xid_cache_insert(list+i, XA_PREPARED);
found_foreign_xids++;
continue;
}
@@ -1070,10 +1071,8 @@ bool mysql_xa_recover(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
- handlerton **ht= handlertons, **end_ht=ht+total_ha;
- bool error=TRUE;
- int len, got;
- XID *list=0;
+ int i=0;
+ XID_STATE *xs;
DBUG_ENTER("mysql_xa_recover");
field_list.push_back(new Item_int("formatID",0,11));
@@ -1083,48 +1082,30 @@ bool mysql_xa_recover(THD *thd)
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
-
- for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
- {
- list=(XID *)my_malloc(len*sizeof(XID), MYF(0));
- }
- if (!list)
- {
- my_error(ER_OUTOFMEMORY, MYF(0), len);
DBUG_RETURN(1);
- }
- for ( ; ht < end_ht ; ht++)
+ pthread_mutex_lock(&LOCK_xid_cache);
+ while ((xs= (XID_STATE*)hash_element(&xid_cache, i++)))
{
- if (!(*ht)->recover)
- continue;
- while ((got=(*(*ht)->recover)(list, len)) > 0 )
+ if (xs->xa_state==XA_PREPARED)
{
- XID *xid, *end;
- for (xid=list, end=list+got; xid < end; xid++)
+ protocol->prepare_for_resend();
+ protocol->store_longlong((longlong)xs->xid.formatID, FALSE);
+ protocol->store_longlong((longlong)xs->xid.gtrid_length, FALSE);
+ protocol->store_longlong((longlong)xs->xid.bqual_length, FALSE);
+ protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length,
+ &my_charset_bin);
+ if (protocol->write())
{
- if (xid->get_my_xid())
- continue; // skip "our" xids
- protocol->prepare_for_resend();
- protocol->store_longlong((longlong)xid->formatID, FALSE);
- protocol->store_longlong((longlong)xid->gtrid_length, FALSE);
- protocol->store_longlong((longlong)xid->bqual_length, FALSE);
- protocol->store(xid->data, xid->gtrid_length+xid->bqual_length,
- &my_charset_bin);
- if (protocol->write())
- goto err;
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ DBUG_RETURN(1);
}
- if (got < len)
- break;
}
}
- error=FALSE;
+ pthread_mutex_unlock(&LOCK_xid_cache);
send_eof(thd);
-err:
- my_free((gptr)list, MYF(0));
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
}
/*
@@ -1827,7 +1808,7 @@ void handler::print_error(int error, myf errflag)
}
case HA_ERR_NULL_IN_SPATIAL:
textno= ER_UNKNOWN_ERROR;
- DBUG_VOID_RETURN;
+ break;
case HA_ERR_FOUND_DUPP_UNIQUE:
textno=ER_DUP_UNIQUE;
break;
@@ -1850,8 +1831,8 @@ void handler::print_error(int error, myf errflag)
textno=ER_CRASHED_ON_REPAIR;
break;
case HA_ERR_OUT_OF_MEM:
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), errflag);
- DBUG_VOID_RETURN;
+ textno=ER_OUT_OF_RESOURCES;
+ break;
case HA_ERR_WRONG_COMMAND:
textno=ER_ILLEGAL_HA;
break;
@@ -1862,10 +1843,8 @@ void handler::print_error(int error, myf errflag)
textno=ER_UNSUPPORTED_EXTENSION;
break;
case HA_ERR_RECORD_FILE_FULL:
- textno=ER_RECORD_FILE_FULL;
- break;
case HA_ERR_INDEX_FILE_FULL:
- textno= errno;
+ textno=ER_RECORD_FILE_FULL;
break;
case HA_ERR_LOCK_WAIT_TIMEOUT:
textno=ER_LOCK_WAIT_TIMEOUT;
diff --git a/sql/handler.h b/sql/handler.h
index 90f3709d2bb..38bb79dbdbc 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -240,11 +240,11 @@ struct xid_t {
char data[XIDDATASIZE]; // not \0-terminated !
bool eq(struct xid_t *xid)
- { return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); }
+ { return !memcmp(this, xid, length()); }
bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(struct xid_t *xid)
- { memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); }
+ { memcpy(this, xid, xid->length()); }
void set(long f, const char *g, long gl, const char *b, long bl)
{
formatID= f;
@@ -283,6 +283,11 @@ struct xid_t {
!memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ?
quick_get_my_xid() : 0;
}
+ uint length()
+ {
+ return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
+ gtrid_length+bqual_length;
+ }
};
typedef struct xid_t XID;
diff --git a/sql/init.cc b/sql/init.cc
index 4beb8db0c6f..e53eeab8902 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -39,12 +39,11 @@ void unireg_init(ulong options)
#endif
VOID(strmov(reg_ext,".frm"));
- specialflag=SPECIAL_SAME_DB_NAME;
+ specialflag=SPECIAL_SAME_DB_NAME | options; /* Set options from argv */
/* Make a tab of powers of 10 */
for (i=0,nr=1.0; i < array_elements(log_10) ; i++)
{ /* It's used by filesort... */
log_10[i]= nr ; nr*= 10.0;
}
- specialflag|=options; /* Set options from argv */
DBUG_VOID_RETURN;
}
diff --git a/sql/item.cc b/sql/item.cc
index d00fcb75d32..f25734fb549 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1016,14 +1016,18 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
; // Do nothing
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
- derivation < dt.derivation &&
- collation->state & MY_CS_UNICODE)
+ collation->state & MY_CS_UNICODE &&
+ (derivation < dt.derivation ||
+ (derivation == dt.derivation &&
+ !(dt.collation->state & MY_CS_UNICODE))))
{
// Do nothing
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
- dt.derivation < derivation &&
- dt.collation->state & MY_CS_UNICODE)
+ dt.collation->state & MY_CS_UNICODE &&
+ (dt.derivation < derivation ||
+ (dt.derivation == derivation &&
+ !(collation->state & MY_CS_UNICODE))))
{
set(dt);
}
@@ -2134,7 +2138,7 @@ 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_client= fromcs;
+ value.cs_info.character_set_of_placeholder= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
@@ -2452,10 +2456,17 @@ const String *Item_param::query_val_str(String* str) const
buf= str->c_ptr_quick();
ptr= buf;
- *ptr++= '\'';
- ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0,
- str_value.ptr(), str_value.length());
- *ptr++= '\'';
+ if (value.cs_info.character_set_client->escape_with_backslash_is_dangerous)
+ {
+ ptr= str_to_hex(ptr, str_value.ptr(), str_value.length());
+ }
+ else
+ {
+ *ptr++= '\'';
+ ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0,
+ str_value.ptr(), str_value.length());
+ *ptr++='\'';
+ }
str->length((uint32) (ptr - buf));
break;
}
@@ -2485,10 +2496,10 @@ bool Item_param::convert_str_value(THD *thd)
here only if conversion is really necessary.
*/
if (value.cs_info.final_character_set_of_str_value !=
- value.cs_info.character_set_client)
+ value.cs_info.character_set_of_placeholder)
{
rc= thd->convert_string(&str_value,
- value.cs_info.character_set_client,
+ value.cs_info.character_set_of_placeholder,
value.cs_info.final_character_set_of_str_value);
}
else
@@ -3067,7 +3078,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
expression to 'reference', i.e. it substitute that expression instead
of this Item_field
*/
- if ((from_field= find_field_in_tables(thd, this, context->table_list,
+ if ((from_field= find_field_in_tables(thd, this,
+ context->first_name_resolution_table,
+ context->last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
!any_privileges &&
@@ -3076,13 +3089,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
not_found_field)
{
/*
- If there is an outer contexts (outer selects, but current select is
+ If there are outer contexts (outer selects, but current select is
not derived table or view) try to resolve this reference in the
outer contexts.
We treat each subselect as a separate namespace, so that different
- subselects may contain columns with the same names. The subselects are
- searched starting from the innermost.
+ subselects may contain columns with the same names. The subselects
+ are searched starting from the innermost.
*/
Name_resolution_context *last_checked_context= context;
Item **ref= (Item **) not_found_item;
@@ -3111,7 +3124,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
(!select->with_sum_func &&
select->group_list.elements == 0)) &&
(from_field= find_field_in_tables(thd, this,
- outer_context->table_list,
+ outer_context->
+ first_name_resolution_table,
+ outer_context->
+ last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
outer_context->
@@ -3186,7 +3202,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
else
{
/* Call find_field_in_tables only to report the error */
- find_field_in_tables(thd, this, context->table_list,
+ find_field_in_tables(thd, this,
+ context->first_name_resolution_table,
+ context->last_name_resolution_table,
reference, REPORT_ALL_ERRORS,
!any_privileges &&
context->check_privileges, TRUE);
@@ -4359,7 +4377,10 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
expression instead of this Item_ref
*/
from_field= find_field_in_tables(thd, this,
- outer_context->table_list,
+ outer_context->
+ first_name_resolution_table,
+ outer_context->
+ last_name_resolution_table,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
outer_context->check_privileges,
@@ -4978,9 +4999,8 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
Try to find field by its name and if it will be found
set field_idx properly.
*/
- (void)find_field_in_real_table(thd, table, field_name,
- (uint) strlen(field_name),
- 0, 0, &field_idx);
+ (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
+ 0, 0, &field_idx);
thd->set_query_id= save_set_query_id;
triggers= table->triggers;
}
diff --git a/sql/item.h b/sql/item.h
index f0ffb160553..ebcd5a9da33 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -237,7 +237,7 @@ void view_error_processor(THD *thd, void *data);
structure before and after INSERT/CREATE and its SELECT to make correct
field name resolution.
*/
-struct Name_resolution_context
+struct Name_resolution_context: Sql_alloc
{
/*
The name resolution context to search in when an Item cannot be
@@ -254,6 +254,19 @@ struct Name_resolution_context
name resolution of different parts of the statement.
*/
TABLE_LIST *table_list;
+ /*
+ In most cases the two table references below replace 'table_list' above
+ for the purpose of name resolution. The first and last name resolution
+ table references allow us to search only in a sub-tree of the nested
+ join tree in a FROM clause. This is needed for NATURAL JOIN, JOIN ... USING
+ and JOIN ... ON.
+ */
+ TABLE_LIST *first_name_resolution_table;
+ /*
+ Last table to search in the list of leaf table references that begins
+ with first_name_resolution_table.
+ */
+ TABLE_LIST *last_name_resolution_table;
/*
SELECT_LEX item belong to, in case of merged VIEW it can differ from
@@ -293,11 +306,13 @@ struct Name_resolution_context
{
resolve_in_select_list= FALSE;
error_processor= &dummy_error_processor;
+ first_name_resolution_table= NULL;
+ last_name_resolution_table= NULL;
}
void resolve_in_table_list_only(TABLE_LIST *tables)
{
- table_list= tables;
+ table_list= first_name_resolution_table= tables;
resolve_in_select_list= FALSE;
}
@@ -657,7 +672,8 @@ public:
current value and pointer passed via parameter otherwise.
*/
virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
- virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
+ /* For SPs mostly. */
+ virtual Item *this_const_item() const { return const_cast<Item*>(this); }
// Row emulation
virtual uint cols() { return 1; }
@@ -828,6 +844,10 @@ public:
void print(String *str);
virtual bool change_context_processor(byte *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
+ friend bool insert_fields(THD *thd, Name_resolution_context *context,
+ const char *db_name,
+ const char *table_name, List_iterator<Item> *it,
+ bool any_privileges);
};
class Item_equal;
@@ -1006,6 +1026,7 @@ public:
struct CONVERSION_INFO
{
CHARSET_INFO *character_set_client;
+ CHARSET_INFO *character_set_of_placeholder;
/*
This points at character set of connection if conversion
to it is required (i. e. if placeholder typecode is not BLOB).
@@ -1129,7 +1150,8 @@ public:
void cleanup() {}
void print(String *str);
Item_num *neg() { value= -value; return this; }
- uint decimal_precision() const { return (uint)(max_length - test(value < 0)); }
+ uint decimal_precision() const
+ { return (uint)(max_length - test(value < 0)); }
bool eq(const Item *, bool binary_cmp) const;
};
@@ -1566,6 +1588,15 @@ public:
bool val_bool();
bool get_date(TIME *ltime, uint fuzzydate);
void print(String *str);
+ /*
+ we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
+ */
+ table_map used_tables() const
+ {
+ return (depended_from ?
+ OUTER_REF_TABLE_BIT :
+ (*ref)->used_tables() | RAND_TABLE_BIT);
+ }
};
class Item_null_helper :public Item_ref_null_helper
@@ -1647,7 +1678,9 @@ public:
longlong val_int()
{
int err;
- return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
+ return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),
+ str_value.length(),10, (char**) 0,
+ &err);
}
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d430d0d3c23..9443a2949d8 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -614,19 +614,38 @@ int Arg_comparator::compare_e_int_diff_signedness()
int Arg_comparator::compare_row()
{
int res= 0;
+ bool was_null= 0;
(*a)->bring_value();
(*b)->bring_value();
uint n= (*a)->cols();
for (uint i= 0; i<n; i++)
{
- if ((res= comparators[i].compare()))
- return res;
+ res= comparators[i].compare();
if (owner->null_value)
- return -1;
+ {
+ // NULL was compared
+ if (owner->abort_on_null)
+ return -1; // We do not need correct NULL returning
+ was_null= 1;
+ owner->null_value= 0;
+ res= 0; // continue comparison (maybe we will meet explicit difference)
+ }
+ else if (res)
+ return res;
}
- return res;
+ if (was_null)
+ {
+ /*
+ There was NULL(s) in comparison in some parts, but there was not
+ explicit difference in other parts, so we have to return NULL
+ */
+ owner->null_value= 1;
+ return -1;
+ }
+ return 0;
}
+
int Arg_comparator::compare_e_row()
{
(*a)->bring_value();
@@ -1903,6 +1922,8 @@ in_row::~in_row()
byte *in_row::get_value(Item *item)
{
tmp.store_value(item);
+ if (item->is_null())
+ return 0;
return (byte *)&tmp;
}
@@ -2791,7 +2812,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
/* If we are on execution stage */
String *escape_str= escape_item->val_str(&tmp_value1);
escape= escape_str ? *(escape_str->ptr()) : '\\';
-
+
/*
We could also do boyer-more for non-const items, but as we would have to
recompute the tables for each row it's not worth it.
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 75c8411b844..6b0cf3e80c2 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -193,10 +193,11 @@ class Item_bool_func2 :public Item_int_func
protected:
Arg_comparator cmp;
String tmp_value1,tmp_value2;
+ bool abort_on_null;
public:
Item_bool_func2(Item *a,Item *b)
- :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {}
+ :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {}
void fix_length_and_dec();
void set_cmp_func()
{
@@ -210,6 +211,7 @@ public:
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
uint decimal_precision() const { return 1; }
+ void top_level_item() { abort_on_null=1; }
friend class Arg_comparator;
};
@@ -913,6 +915,11 @@ public:
longlong val_int();
const char *func_name() const { return "<is_not_null_test>"; }
void update_used_tables();
+ /*
+ we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
+ */
+ table_map used_tables() const
+ { return used_tables_cache | RAND_TABLE_BIT; }
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index b7d8d50f9b3..77476e41d0b 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -354,6 +354,12 @@ Item *create_func_sha(Item* a)
return new Item_func_sha(a);
}
+Item *create_func_sleep(Item* a)
+{
+ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return new Item_func_sleep(a);
+}
+
Item *create_func_space(Item *a)
{
CHARSET_INFO *cs= current_thd->variables.collation_connection;
diff --git a/sql/item_create.h b/sql/item_create.h
index 0a9af144ec0..d757318bfc1 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -83,6 +83,7 @@ Item *create_func_sec_to_time(Item* a);
Item *create_func_sign(Item* a);
Item *create_func_sin(Item* a);
Item *create_func_sha(Item* a);
+Item *create_func_sleep(Item* a);
Item *create_func_soundex(Item* a);
Item *create_func_space(Item *);
Item *create_func_sqrt(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 71e0f29ffc7..d3b53db2d54 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1873,6 +1873,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
Allocate rand structure once: we must use thd->current_arena
to create rand in proper mem_root if it's a prepared statement or
stored procedure.
+
+ No need to send a Rand log event if seed was given eg: RAND(seed),
+ as it will be replicated in the query as such.
*/
if (!rand && !(rand= (struct rand_struct*)
thd->current_arena->alloc(sizeof(*rand))))
@@ -1895,16 +1898,16 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
else
{
/*
- No need to send a Rand log event if seed was given eg: RAND(seed),
- as it will be replicated in the query as such.
-
Save the seed only the first time RAND() is used in the query
Once events are forwarded rather than recreated,
the following can be skipped if inside the slave thread
*/
- thd->rand_used=1;
- thd->rand_saved_seed1=thd->rand.seed1;
- thd->rand_saved_seed2=thd->rand.seed2;
+ if (!thd->rand_used)
+ {
+ thd->rand_used= 1;
+ thd->rand_saved_seed1= thd->rand.seed1;
+ thd->rand_saved_seed2= thd->rand.seed2;
+ }
rand= &thd->rand;
}
return FALSE;
@@ -3259,6 +3262,43 @@ void Item_func_benchmark::print(String *str)
str->append(')');
}
+/* This function is just used to create tests with time gaps */
+
+longlong Item_func_sleep::val_int()
+{
+ THD *thd= current_thd;
+ struct timespec abstime;
+ pthread_cond_t cond;
+ int error;
+
+ DBUG_ASSERT(fixed == 1);
+
+ double time= args[0]->val_real();
+ set_timespec_nsec(abstime, (ulonglong)(time * ULL(1000000000)));
+
+ pthread_cond_init(&cond, NULL);
+ pthread_mutex_lock(&LOCK_user_locks);
+
+ thd->mysys_var->current_mutex= &LOCK_user_locks;
+ thd->mysys_var->current_cond= &cond;
+
+ while (!thd->killed &&
+ (error= pthread_cond_timedwait(&cond, &LOCK_user_locks,
+ &abstime)) != ETIMEDOUT &&
+ error != EINVAL) ;
+
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ pthread_mutex_unlock(&LOCK_user_locks);
+ pthread_cond_destroy(&cond);
+
+ return (error == ETIMEDOUT) ? 0 : 1;
+}
+
+
#define extra_size sizeof(double)
static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
@@ -4654,10 +4694,9 @@ Item_func_sp::execute(Item **itp)
{
DBUG_ENTER("Item_func_sp::execute");
THD *thd= current_thd;
- ulong old_client_capabilites;
int res= -1;
- bool save_in_sub_stmt= thd->in_sub_stmt;
- my_bool save_no_send_ok;
+ Sub_statement_state statement_state;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
st_sp_security_context save_ctx;
#endif
@@ -4668,38 +4707,21 @@ Item_func_sp::execute(Item **itp)
goto error;
}
- old_client_capabilites= thd->client_capabilities;
- thd->client_capabilities &= ~CLIENT_MULTI_RESULTS;
-
-#ifndef EMBEDDED_LIBRARY
- save_no_send_ok= thd->net.no_send_ok;
- thd->net.no_send_ok= TRUE;
-#endif
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, 0))
- goto error_check;
+ goto error;
sp_change_security_context(thd, m_sp, &save_ctx);
if (save_ctx.changed &&
check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, 0))
goto error_check_ctx;
#endif
- /*
- Like for SPs, we don't binlog the substatements. If the statement which
- called this function is an update statement, it will be binlogged; but if
- it's not (e.g. SELECT myfunc()) it won't be binlogged (documented known
- problem).
- */
-
- tmp_disable_binlog(thd); /* don't binlog the substatements */
- thd->in_sub_stmt= TRUE;
+ thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
res= m_sp->execute_function(thd, args, arg_count, itp);
+ thd->restore_sub_statement_state(&statement_state);
- thd->in_sub_stmt= save_in_sub_stmt;
- reenable_binlog(thd);
if (res && mysql_bin_log.is_open() &&
(m_sp->m_chistics->daccess == SP_CONTAINS_SQL ||
m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
@@ -4712,15 +4734,6 @@ error_check_ctx:
sp_restore_security_context(thd, m_sp, &save_ctx);
#endif
- thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
-
-error_check:
-#ifndef EMBEDDED_LIBRARY
- thd->net.no_send_ok= save_no_send_ok;
-#endif
-
- thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
-
error:
DBUG_RETURN(res);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index e8db9d70ae7..384cb486f7c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -874,6 +874,7 @@ public:
}
};
+
class Item_func_benchmark :public Item_int_func
{
ulong loop_count;
@@ -888,6 +889,22 @@ public:
};
+class Item_func_sleep :public Item_int_func
+{
+public:
+ Item_func_sleep(Item *a) :Item_int_func(a) {}
+ bool const_item() const { return 0; }
+ const char *func_name() const { return "sleep"; }
+ void update_used_tables()
+ {
+ Item_int_func::update_used_tables();
+ used_tables_cache|= RAND_TABLE_BIT;
+ }
+ longlong val_int();
+};
+
+
+
#ifdef HAVE_DLOPEN
class Item_udf_func :public Item_func
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 256090d3e61..094a0c56319 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1177,11 +1177,23 @@ String *Item_func_substr_index::val_str(String *str)
}
}
else
- { // Start counting at end
- for (offset=res->length() ; ; offset-=delimeter_length-1)
+ {
+ /*
+ Negative index, start counting at the end
+ */
+ for (offset=res->length(); offset ;)
{
+ /*
+ this call will result in finding the position pointing to one
+ address space less than where the found substring is located
+ in res
+ */
if ((int) (offset=res->strrstr(*delimeter,offset)) < 0)
return res; // Didn't find, return org string
+ /*
+ At this point, we've searched for the substring
+ the number of times as supplied by the index value
+ */
if (!++count)
{
offset+=delimeter_length;
@@ -1558,6 +1570,7 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
return NULL;
}
conv->str_value.copy();
+ conv->str_value.mark_as_const();
return conv;
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 903f4c953a2..7e47de494db 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -969,6 +969,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ select_lex->where->top_level_item();
/*
we do not check join->conds->fixed, because Item_and can't be fixed
after creation
@@ -1032,8 +1033,12 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Item_subselect::trans_res
Item_in_subselect::row_value_transformer(JOIN *join)
{
- Item *item= 0;
SELECT_LEX *select_lex= join->select_lex;
+ Item *having_item= 0;
+ uint cols_num= left_expr->cols();
+ bool is_having_used= (join->having || select_lex->with_sum_func ||
+ select_lex->group_list.first ||
+ !select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::row_value_transformer");
if (select_lex->item_list.elements != left_expr->cols())
@@ -1065,66 +1070,164 @@ Item_in_subselect::row_value_transformer(JOIN *join)
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
+ if (is_having_used)
{
- uint n= left_expr->cols();
- List_iterator_fast<Item> li(select_lex->item_list);
- for (uint i= 0; i < n; i++)
+ /*
+ (l1, l2, l3) IN (SELECT v1, v2, v3 ... HAVING having) =>
+ EXISTS (SELECT ... HAVING having and
+ (l1 = v1 or is null v1) and
+ (l2 = v2 or is null v2) and
+ (l3 = v3 or is null v3) and
+ is_not_null_test(v1) and
+ is_not_null_test(v2) and
+ is_not_null_test(v3))
+ where is_not_null_test used to register nulls in case if we have
+ not found matching to return correct NULL value
+ */
+ Item *item_having_part2= 0;
+ for (uint i= 0; i < cols_num; i++)
{
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
check_cols(left_expr->el(i)->cols()))
DBUG_RETURN(RES_ERROR);
- Item *func= new Item_ref_null_helper(&select_lex->context,
- this,
- select_lex->ref_pointer_array+i,
- (char *) "<no matter>",
- (char *) "<list ref>");
- func=
- eq_creator.create(new Item_direct_ref(&select_lex->context,
- (*optimizer->get_cache())->
- addr(i),
- (char *)"<no matter>",
- (char *)in_left_expr_name),
- func);
- item= and_items(item, func);
+ Item *item_eq=
+ new Item_func_eq(new
+ Item_direct_ref(&select_lex->context,
+ (*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
+ new
+ Item_direct_ref(&select_lex->context,
+ select_lex->ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ Item *item_isnull=
+ new Item_func_isnull(new
+ Item_direct_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ having_item=
+ and_items(having_item,
+ new Item_cond_or(item_eq, item_isnull));
+ item_having_part2=
+ and_items(item_having_part2,
+ new
+ Item_is_not_null_test(this,
+ new
+ Item_direct_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ )
+ );
+ item_having_part2->top_level_item();
}
+ having_item= and_items(having_item, item_having_part2);
+ having_item->top_level_item();
}
- if (join->having || select_lex->with_sum_func ||
- select_lex->group_list.first ||
- !select_lex->table_list.elements)
+ else
{
/*
- AND can't be changed during fix_fields()
- we can assign select_lex->having here, and pass 0 as last
- argument (reference) to fix_fields()
+ (l1, l2, l3) IN (SELECT v1, v2, v3 ... WHERE where) =>
+ EXISTS (SELECT ... WHERE where and
+ (l1 = v1 or is null v1) and
+ (l2 = v2 or is null v2) and
+ (l3 = v3 or is null v3)
+ HAVING is_not_null_test(v1) and
+ is_not_null_test(v2) and
+ is_not_null_test(v3))
+ where is_not_null_test register NULLs values but reject rows
+
+ in case when we do not need correct NULL, we have simplier construction:
+ EXISTS (SELECT ... WHERE where and
+ (l1 = v1) and
+ (l2 = v2) and
+ (l3 = v3)
*/
- select_lex->having= join->having= and_items(join->having, item);
- select_lex->having_fix_field= 1;
+ Item *where_item= 0;
+ for (uint i= 0; i < cols_num; i++)
+ {
+ Item *item, *item_isnull;
+ DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
+ if (select_lex->ref_pointer_array[i]->
+ check_cols(left_expr->el(i)->cols()))
+ DBUG_RETURN(RES_ERROR);
+ item=
+ new Item_func_eq(new
+ Item_direct_ref(&select_lex->context,
+ (*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
+ new
+ Item_direct_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ if (!abort_on_null)
+ {
+ having_item=
+ and_items(having_item,
+ new
+ Item_is_not_null_test(this,
+ new
+ Item_direct_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ )
+ );
+ item_isnull= new
+ Item_func_isnull(new
+ Item_direct_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+
+ item= new Item_cond_or(item, item_isnull);
+ }
+
+ where_item= and_items(where_item, item);
+ }
/*
- join->having can't be fixed after creation, so we do not check
- join->having->fixed
+ AND can't be changed during fix_fields()
+ we can assign select_lex->where here, and pass 0 as last
+ argument (reference) to fix_fields()
*/
- if (join->having->fix_fields(thd, 0))
- {
- select_lex->having_fix_field= 0;
+ select_lex->where= join->conds= and_items(join->conds, where_item);
+ select_lex->where->top_level_item();
+ if (join->conds->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
- }
- select_lex->having_fix_field= 0;
}
- else
+ if (having_item)
{
+ bool res;
+ select_lex->having= join->having= and_items(join->having, having_item);
+ select_lex->having->top_level_item();
/*
AND can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
*/
- select_lex->where= join->conds= and_items(join->conds, item);
- /*
- join->conds can't be fixed after creation, so we do not check
- join->conds->fixed
- */
- if (join->conds->fix_fields(thd, 0))
+ select_lex->having_fix_field= 1;
+ res= join->having->fix_fields(thd, 0);
+ select_lex->having_fix_field= 0;
+ if (res)
+ {
DBUG_RETURN(RES_ERROR);
+ }
}
DBUG_RETURN(RES_OK);
@@ -1271,6 +1374,14 @@ void Item_allany_subselect::print(String *str)
}
+void subselect_engine::set_thd(THD *thd_arg)
+{
+ thd= thd_arg;
+ if (result)
+ result->set_thd(thd_arg);
+}
+
+
subselect_single_select_engine::
subselect_single_select_engine(st_select_lex *select,
select_subselect *result,
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 0b5736169fa..46623f76170 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -299,8 +299,11 @@ public:
virtual ~subselect_engine() {}; // to satisfy compiler
virtual void cleanup()= 0;
- // set_thd should be called before prepare()
- void set_thd(THD *thd_arg) { thd= thd_arg; }
+ /*
+ Also sets "thd" for subselect_engine::result.
+ Should be called before prepare().
+ */
+ void set_thd(THD *thd_arg);
THD * get_thd() { return thd; }
virtual int prepare()= 0;
virtual void fix_length_and_dec(Item_cache** row)= 0;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index bbcea4705fa..e86d4f0d8ba 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -2291,7 +2291,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
DBUG_ASSERT(table == 0);
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
0,
- select_lex->options | thd->options,
+ (select_lex->options | thd->options),
HA_POS_ERROR, (char*)"")))
return TRUE;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
@@ -3073,7 +3073,7 @@ bool Item_func_group_concat::setup(THD *thd)
*/
if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
(ORDER*) 0, 0, TRUE,
- select_lex->options | thd->options,
+ (select_lex->options | thd->options),
HA_POS_ERROR, (char*) "")))
DBUG_RETURN(TRUE);
table->file->extra(HA_EXTRA_NO_ROWS);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index a6fbbee6f23..0d9e23ff0a1 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1476,9 +1476,9 @@ void Item_func_now_utc::store_now_in_TIME(TIME *now_time)
bool Item_func_now::get_date(TIME *res,
- uint fuzzy_date __attribute__((unused)))
+ uint fuzzy_date __attribute__((unused)))
{
- *res=ltime;
+ *res= ltime;
return 0;
}
@@ -1491,6 +1491,70 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
}
+/*
+ Converts current time in my_time_t to TIME represenatation for local
+ time zone. Defines time zone (local) used for whole SYSDATE function.
+*/
+void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time)
+{
+ THD *thd= current_thd;
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL));
+ thd->time_zone_used= 1;
+}
+
+
+String *Item_func_sysdate_local::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ store_now_in_TIME(&ltime);
+ buff_length= (uint) my_datetime_to_str(&ltime, buff);
+ str_value.set(buff, buff_length, &my_charset_bin);
+ return &str_value;
+}
+
+
+longlong Item_func_sysdate_local::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ store_now_in_TIME(&ltime);
+ return (longlong) TIME_to_ulonglong_datetime(&ltime);
+}
+
+
+double Item_func_sysdate_local::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ store_now_in_TIME(&ltime);
+ return (longlong) TIME_to_ulonglong_datetime(&ltime);
+}
+
+
+void Item_func_sysdate_local::fix_length_and_dec()
+{
+ decimals= 0;
+ collation.set(&my_charset_bin);
+ max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+}
+
+
+bool Item_func_sysdate_local::get_date(TIME *res,
+ uint fuzzy_date __attribute__((unused)))
+{
+ store_now_in_TIME(&ltime);
+ *res= ltime;
+ return 0;
+}
+
+
+int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
+{
+ store_now_in_TIME(&ltime);
+ to->set_notnull();
+ to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
+ return 0;
+}
+
+
String *Item_func_sec_to_time::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1938,7 +2002,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
/* Day number from year 0 to 9999-12-31 */
if ((ulonglong) daynr >= MAX_DAY_NUMBER)
- goto null_date;
+ goto invalid_date;
get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
&ltime->day);
break;
@@ -1949,13 +2013,13 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
sign * (long) interval.day);
/* Daynumber from year 0 to 9999-12-31 */
if ((ulong) period >= MAX_DAY_NUMBER)
- goto null_date;
+ goto invalid_date;
get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
break;
case INTERVAL_YEAR:
ltime->year+= sign * (long) interval.year;
if ((ulong) ltime->year >= 10000L)
- goto null_date;
+ goto invalid_date;
if (ltime->month == 2 && ltime->day == 29 &&
calc_days_in_year(ltime->year) != 366)
ltime->day=28; // Was leap-year
@@ -1966,7 +2030,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
period= (ltime->year*12 + sign * (long) interval.year*12 +
ltime->month-1 + sign * (long) interval.month);
if ((ulong) period >= 120000L)
- goto null_date;
+ goto invalid_date;
ltime->year= (uint) (period / 12);
ltime->month= (uint) (period % 12L)+1;
/* Adjust day if the new month doesn't have enough days */
@@ -1982,6 +2046,11 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
}
return 0; // Ok
+invalid_date:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_DATETIME_FUNCTION_OVERFLOW,
+ ER(ER_DATETIME_FUNCTION_OVERFLOW),
+ "datetime");
null_date:
return (null_value=1);
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 107d12e6da2..4602088a5f5 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -446,6 +446,7 @@ public:
class Item_func_now :public Item_date_func
{
+protected:
longlong value;
char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy
uint buff_length;
@@ -485,6 +486,32 @@ public:
};
+/*
+ This is like NOW(), but always uses the real current time, not the
+ query_start(). This matches the Oracle behavior.
+*/
+class Item_func_sysdate_local :public Item_func_now
+{
+public:
+ Item_func_sysdate_local() :Item_func_now() {}
+ Item_func_sysdate_local(Item *a) :Item_func_now(a) {}
+ bool const_item() const { return 0; }
+ const char *func_name() const { return "sysdate"; }
+ void store_now_in_TIME(TIME *now_time);
+ double val_real();
+ longlong val_int();
+ int save_in_field(Field *to, bool no_conversions);
+ String *val_str(String *str);
+ void fix_length_and_dec();
+ bool get_date(TIME *res, uint fuzzy_date);
+ void update_used_tables()
+ {
+ Item_func_now::update_used_tables();
+ used_tables_cache|= RAND_TABLE_BIT;
+ }
+};
+
+
class Item_func_from_days :public Item_date
{
public:
@@ -714,6 +741,12 @@ public:
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
+ void fix_length_and_dec()
+ {
+ collation.set(&my_charset_bin);
+ max_length= 10;
+ maybe_null= 1;
+ }
};
@@ -854,7 +887,7 @@ class Item_func_timestamp_diff :public Item_int_func
public:
Item_func_timestamp_diff(Item *a,Item *b,interval_type type_arg)
:Item_int_func(a,b), int_type(type_arg) {}
- const char *func_name() const { return "timestamp_diff"; }
+ const char *func_name() const { return "timestampdiff"; }
longlong val_int();
void fix_length_and_dec()
{
diff --git a/sql/lex.h b/sql/lex.h
index 3160b9efdcb..f0a6c0047d2 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -748,6 +748,7 @@ static SYMBOL sql_functions[] = {
{ "SIN", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sin)},
{ "SHA", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sha)},
{ "SHA1", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sha)},
+ { "SLEEP", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sleep)},
{ "SOUNDEX", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)},
{ "SPACE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)},
{ "SQRT", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)},
@@ -764,7 +765,7 @@ static SYMBOL sql_functions[] = {
{ "SUBSTRING_INDEX", SYM(SUBSTRING_INDEX)},
{ "SUBTIME", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_subtime)},
{ "SUM", SYM(SUM_SYM)},
- { "SYSDATE", SYM(NOW_SYM)},
+ { "SYSDATE", SYM(SYSDATE)},
{ "SYSTEM_USER", SYM(USER)},
{ "TAN", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_tan)},
{ "TIME_FORMAT", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 29b6473d7d4..0aba7fddb51 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -848,10 +848,6 @@ static void print_lock_error(int error, const char *table)
So in this exceptional case the COMMIT should not be blocked by the FLUSH
TABLES WITH READ LOCK.
- TODO in MySQL 5.x: make_global_read_lock_block_commit() should be
- killable. Normally CPU does not spend a long time in this function (COMMITs
- are quite fast), but it would still be nice.
-
****************************************************************************/
volatile uint global_read_lock=0;
@@ -1002,7 +998,7 @@ bool make_global_read_lock_block_commit(THD *thd)
pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
protect_against_global_read_lock--;);
- if (error= thd->killed)
+ if ((error= test(thd->killed)))
global_read_lock_blocks_commit--; // undo what we did
else
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 29f1160466e..55006a7c9be 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -211,7 +211,7 @@ static inline int read_str(char **buf, char *buf_end, char **str,
/*
Transforms a string into "" or its expression in 0x... form.
*/
-static char *str_to_hex(char *to, char *from, uint len)
+char *str_to_hex(char *to, const char *from, uint len)
{
char *p= to;
if (len)
@@ -1329,10 +1329,20 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
}
}
+#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE)
if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
time_zone_len + 1 +
- data_len + 1, MYF(MY_WME))))
- DBUG_VOID_RETURN;
+ data_len + 1 +
+ QUERY_CACHE_FLAGS_SIZE +
+ db_len + 1,
+ MYF(MY_WME))))
+#else
+ if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
+ time_zone_len + 1 +
+ data_len + 1,
+ MYF(MY_WME))))
+#endif
+ DBUG_VOID_RETURN;
if (catalog_len) // If catalog is given
{
if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3.
diff --git a/sql/log_event.h b/sql/log_event.h
index 9f4681ae2c5..1d8941e65ac 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -393,6 +393,10 @@ struct sql_ex_info
#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \
OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS)
+#if OPTIONS_WRITTEN_TO_BIN_LOG != ((1L << 14) | (1L << 26) | (1L << 27))
+#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values!
+#endif
+
enum Log_event_type
{
/*
@@ -1578,5 +1582,5 @@ public:
bool is_valid() const { return 1; }
};
#endif
-
+char *str_to_hex(char *to, const char *from, uint len);
#endif /* _log_event_h */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 46a4a08a30c..b3d107365c9 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -284,6 +284,11 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern
/* If not set then the thread will ignore all warnings with level notes. */
#define OPTION_SQL_NOTES (1L << 31) // THD, user
+/*
+ Force the used temporary table to be a MyISAM table (because we will use
+ fulltext functions when reading from it.
+*/
+#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32)
/*
Maximum length of time zone name that we support
@@ -494,8 +499,7 @@ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
-void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0,
- TABLE *stopper= 0);
+void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables);
bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
@@ -588,7 +592,7 @@ int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
-bool mysql_change_db(THD *thd,const char *name);
+bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
@@ -743,7 +747,7 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
enum enum_duplicates handle_duplicates, bool ignore);
bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
List<Item> *fields, List<Item> *values,
- COND *conds, ulong options,
+ COND *conds, ulonglong options,
enum enum_duplicates handle_duplicates, bool ignore,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
@@ -759,7 +763,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list);
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order,
- ha_rows rows, ulong options);
+ ha_rows rows, ulonglong options);
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
@@ -784,23 +788,25 @@ extern Field *view_ref_found;
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
IGNORE_EXCEPT_NON_UNIQUE};
-Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- Item **ref,
- find_item_error_report_type report_error,
- bool check_privileges,
- bool register_tree_change);
Field *
-find_field_in_table(THD *thd, TABLE_LIST *table_list,
- const char *name, const char *item_name,
- uint length, Item **ref,
- bool check_grants_table, bool check_grants_view,
- bool allow_rowid,
- uint *cached_field_index_ptr,
- bool register_tree_change);
+find_field_in_tables(THD *thd, Item_ident *item,
+ TABLE_LIST *first_table, TABLE_LIST *last_table,
+ Item **ref, find_item_error_report_type report_error,
+ bool check_privileges, bool register_tree_change);
+Field *
+find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ const char *table_name, const char *db_name,
+ uint length, Item **ref,
+ bool check_grants_table, bool check_grants_view,
+ bool allow_rowid,
+ uint *cached_field_index_ptr,
+ bool register_tree_change, TABLE_LIST **actual_table);
Field *
-find_field_in_real_table(THD *thd, TABLE *table, const char *name,
- uint length, bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr);
+find_field_in_table(THD *thd, TABLE *table, const char *name,
+ uint length, bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr);
+
Field *
find_field_in_table_sef(TABLE *table, const char *name);
@@ -910,8 +916,10 @@ create_field * new_create_field(THD *thd, char *field_name, enum_field_types typ
uint uint_geom_type);
void store_position_for_column(const char *name);
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
+Name_resolution_context *make_join_on_context(THD *thd, TABLE_LIST *left_op,
+ TABLE_LIST *right_op);
void add_join_on(TABLE_LIST *b,Item *expr);
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
@@ -928,8 +936,8 @@ bool insert_fields(THD *thd, Name_resolution_context *context,
const char *db_name, const char *table_name,
List_iterator<Item> *it, bool any_privileges);
bool setup_tables(THD *thd, Name_resolution_context *context,
- TABLE_LIST *tables, Item **conds,
- TABLE_LIST **leaves, bool select_insert);
+ List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
+ Item **conds, TABLE_LIST **leaves, bool select_insert);
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,
@@ -952,10 +960,10 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd);
-int open_tables(THD *thd, TABLE_LIST **tables, uint *counter);
+int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
-bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
@@ -1000,7 +1008,7 @@ bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
bool ignore_errors,
Table_triggers_list *triggers,
enum trg_event_type event);
-OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
const char *db_name,
@@ -1128,6 +1136,7 @@ extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
extern double log_10[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
+extern ulonglong thd_startup_options;
extern ulong refresh_version,flush_version, thread_id;
extern ulong binlog_cache_use, binlog_cache_disk_use;
extern ulong aborted_threads,aborted_connects;
@@ -1137,7 +1146,7 @@ extern ulong delayed_insert_threads, delayed_insert_writes;
extern ulong delayed_rows_in_use,delayed_insert_errors;
extern ulong slave_open_temp_tables;
extern ulong query_cache_size, query_cache_min_res_unit;
-extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
+extern ulong slow_launch_threads, slow_launch_time;
extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout, slave_trans_retries;
@@ -1477,6 +1486,12 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->status= STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->maybe_null= table_list->outer_join;
+ TABLE_LIST *embedding= table_list->embedding;
+ while (!table->maybe_null && embedding)
+ {
+ table->maybe_null= embedding->outer_join;
+ embedding= embedding->embedding;
+ }
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5b8814818bf..7813e654433 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -394,8 +394,8 @@ uint delay_key_write_options, protocol_version;
uint lower_case_table_names;
uint tc_heuristic_recover= 0;
uint volatile thread_count, thread_running;
-ulong back_log, connect_timeout, concurrency;
-ulong server_id, thd_startup_options;
+ulonglong thd_startup_options;
+ulong back_log, connect_timeout, concurrency, server_id;
ulong table_cache_size, thread_stack, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
@@ -720,7 +720,6 @@ static void close_connections(void)
}
#endif
end_thr_alarm(0); // Abort old alarms.
- end_slave();
/*
First signal all threads that it's time to die
@@ -736,6 +735,10 @@ 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)
+ continue;
+
tmp->killed= THD::KILL_CONNECTION;
if (tmp->mysys_var)
{
@@ -752,6 +755,8 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
+ end_slave();
+
if (thread_count)
sleep(2); // Give threads time to die
@@ -1056,6 +1061,7 @@ void clean_up(bool print_message)
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
if (tc_log)
tc_log->close();
+ xid_cache_free();
delete_elements(&key_caches, (void (*)(const char*, gptr)) free_key_cache);
multi_keycache_free();
end_thr_alarm(1); /* Free allocated memory */
@@ -1911,7 +1917,8 @@ static void check_data_home(const char *path)
static void sig_reload(int signo)
{
// Flush everything
- reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, NULL);
+ bool not_used;
+ reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, &not_used);
signal(signo, SIG_ACK);
}
@@ -2270,12 +2277,13 @@ static void *signal_hand(void *arg __attribute__((unused)))
case SIGHUP:
if (!abort_loop)
{
+ bool not_used;
mysql_print_status(); // Print some debug info
reload_acl_and_cache((THD*) 0,
(REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
REFRESH_GRANT |
REFRESH_THREADS | REFRESH_HOSTS),
- (TABLE_LIST*) 0, NULL); // Flush logs
+ (TABLE_LIST*) 0, &not_used); // Flush logs
}
break;
#ifdef USE_ONE_SIGNAL_HAND
@@ -2923,6 +2931,11 @@ server.");
using_update_log=1;
}
+ if (xid_cache_init())
+ {
+ sql_print_error("Out of memory");
+ unireg_abort(1);
+ }
if (ha_init())
{
sql_print_error("Can't init databases");
@@ -5337,6 +5350,10 @@ log and this option does nothing anymore.",
"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},
+ {"innodb_commit_concurrency", OPT_INNODB_THREAD_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},
{"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
" disable a sleep",
diff --git a/sql/set_var.cc b/sql/set_var.cc
index d5c3496eae6..e92ea232759 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -413,6 +413,8 @@ sys_var_long_ptr sys_innodb_thread_sleep_delay("innodb_thread_sleep_delay",
&srv_thread_sleep_delay);
sys_var_long_ptr sys_innodb_thread_concurrency("innodb_thread_concurrency",
&srv_thread_concurrency);
+sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency",
+ &srv_commit_concurrency);
#endif
/* Condition pushdown to storage engine */
@@ -711,6 +713,7 @@ sys_var *sys_variables[]=
&sys_innodb_concurrency_tickets,
&sys_innodb_thread_sleep_delay,
&sys_innodb_thread_concurrency,
+ &sys_innodb_commit_concurrency,
#endif
&sys_trust_routine_creators,
&sys_engine_condition_pushdown,
@@ -832,6 +835,7 @@ struct show_var_st init_vars[]= {
{sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
{sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS},
{sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS},
+ {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS},
{sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS},
#endif
{sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS},
@@ -2298,7 +2302,12 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
if (!tmp) // Zero size means delete
{
if (key_cache == dflt_key_cache)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE,
+ ER(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE));
goto end; // Ignore default key cache
+ }
if (key_cache->key_cache_inited) // If initied
{
@@ -3100,7 +3109,18 @@ int set_var_password::check(THD *thd)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!user->host.str)
- user->host.str= (char*) thd->host_or_ip;
+ {
+ if (thd->priv_host != 0)
+ {
+ user->host.str= (char *) thd->priv_host;
+ user->host.length= strlen(thd->priv_host);
+ }
+ else
+ {
+ user->host.str= (char *)"%";
+ user->host.length= 1;
+ }
+ }
/* Returns 1 as the function sends error to client */
return check_change_password(thd, user->host.str, user->user.str,
password, strlen(password)) ? 1 : 0;
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index b7ab8fead22..2e23027f1f5 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -33,7 +33,7 @@ all-local: english/errmsg.sys
# created. Normally these are created by extra/Makefile
english/errmsg.sys: errmsg.txt
- rm $(top_builddir)/include/mysqld_error.h
+ rm -f $(top_builddir)/include/mysqld_error.h
(cd $(top_builddir)/extra && $(MAKE))
install-data-local:
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index a22e32fb075..ba9005638e1 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5137,8 +5137,8 @@ ER_SP_CANT_ALTER
eng "Failed to ALTER %s %s"
ER_SP_SUBSELECT_NYI 0A000
eng "Subselect value not supported"
-ER_SP_NO_USE 42000
- eng "USE is not allowed in a stored procedure"
+ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 0A000
+ eng "%s is not allowed in stored function or trigger"
ER_SP_VARCOND_AFTER_CURSHNDLR 42000
eng "Variable or condition declaration after cursor or handler declaration"
ER_SP_CURSOR_AFTER_HANDLER 42000
@@ -5194,7 +5194,7 @@ ER_VIEW_SELECT_VARIABLE
rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ"
ukr "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ"
ER_VIEW_SELECT_TMPTABLE
- eng "View's SELECT contains a temporary table '%-.64s'"
+ eng "View's SELECT refers to a temporary table '%-.64s'"
rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'"
ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'"
ER_VIEW_WRONG_LIST
@@ -5342,8 +5342,8 @@ ER_SP_DUP_HANDLER 42000
eng "Duplicate handler declared in the same block"
ER_SP_NOT_VAR_ARG 42000
eng "OUT or INOUT argument %d for routine %s is not a variable"
-ER_SP_NO_RETSET_IN_FUNC 0A000
- eng "Not allowed to return a result set from a function"
+ER_SP_NO_RETSET 0A000
+ eng "Not allowed to return a result set from a %s"
ER_CANT_CREATE_GEOMETRY_OBJECT 22003
eng "Cannot get geometry object from data you send to the GEOMETRY field"
ER_FAILED_ROUTINE_BREAK_BINLOG
@@ -5380,14 +5380,25 @@ ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE
eng "Can't create federated table. The data source connection string '%-.64s' is not in the correct format"
ER_FOREIGN_DATA_STRING_INVALID
eng "The data source connection string '%-.64s' is not in the correct format"
-ER_CANT_CREATE_FEDERATED_TABLE
- eng "Can't create federated table. Foreign data src error : '%-.64s'"
-ER_TRG_IN_WRONG_SCHEMA
- eng "Trigger in wrong schema"
+ER_CANT_CREATE_FEDERATED_TABLE
+ eng "Can't create federated table. Foreign data src error : '%-.64s'"
+ER_TRG_IN_WRONG_SCHEMA
+ eng "Trigger in wrong schema"
ER_STACK_OVERRUN_NEED_MORE
eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack."
ER_TOO_LONG_BODY 42000 S1009
eng "Routine body for '%-.100s' is too long"
+ER_WARN_CANT_DROP_DEFAULT_KEYCACHE
+ eng "Cannot drop default keycache"
+ ger "Der Default-Keycache kann nicht gelöscht werden"
+ER_TOO_BIG_DISPLAYWIDTH 42000 S1009
+ eng "Display width out of range for column '%-.64s' (max = %d)"
+ER_XAER_DUPID XAE08
+ eng "XAER_DUPID: The XID already exists"
+ER_DATETIME_FUNCTION_OVERFLOW 22008
+ eng "Datetime function: %-.32s field overflow"
+ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+ eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
ER_PARTITION_REQUIRES_VALUES_ERROR
eng "%s PARTITIONING requires definition of VALUES %s for each partition"
swe "%s PARTITIONering kräver definition av VALUES %s för varje partition"
diff --git a/sql/slave.cc b/sql/slave.cc
index 2e751f9ddab..757d8bc212d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2018,8 +2018,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
&my_charset_bin);
protocol->store((ulonglong) mi->rli.group_relay_log_pos);
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
- protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT
- ? "Yes":"No", &my_charset_bin);
+ protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ?
+ "Yes" : "No", &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(rpl_filter->get_do_db());
protocol->store(rpl_filter->get_ignore_db());
diff --git a/sql/sp.cc b/sql/sp.cc
index e45a360e85b..4485019be4a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -68,13 +68,16 @@ bool mysql_proc_table_exists= 1;
SYNOPSIS
close_proc_table()
- thd Thread context
+ thd Thread context
+ backup Pointer to Open_tables_state instance which holds
+ information about tables which were open before we
+ decided to access mysql.proc.
*/
-static void close_proc_table(THD *thd)
+void close_proc_table(THD *thd, Open_tables_state *backup)
{
close_thread_tables(thd);
- thd->pop_open_tables_state();
+ thd->restore_backup_open_tables_state(backup);
}
@@ -83,7 +86,10 @@ static void close_proc_table(THD *thd)
SYNOPSIS
open_proc_table_for_read()
- thd Thread context
+ thd Thread context
+ backup Pointer to Open_tables_state instance where information about
+ currently open tables will be saved, and from which will be
+ restored when we will end work with mysql.proc.
NOTES
Thanks to restrictions which we put on opening and locking of
@@ -97,11 +103,10 @@ static void close_proc_table(THD *thd)
# Pointer to TABLE object of mysql.proc
*/
-static TABLE *open_proc_table_for_read(THD *thd)
+TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
{
TABLE_LIST tables;
TABLE *table;
- bool old_open_tables= thd->open_tables != 0;
bool refresh;
DBUG_ENTER("open_proc_table");
@@ -112,8 +117,7 @@ static TABLE *open_proc_table_for_read(THD *thd)
if (!mysql_proc_table_exists)
DBUG_RETURN(0);
- if (thd->push_open_tables_state())
- DBUG_RETURN(0);
+ thd->reset_n_backup_open_tables_state(backup);
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
@@ -121,7 +125,7 @@ static TABLE *open_proc_table_for_read(THD *thd)
if (!(table= open_table(thd, &tables, thd->mem_root, &refresh,
MYSQL_LOCK_IGNORE_FLUSH)))
{
- thd->pop_open_tables_state();
+ thd->restore_backup_open_tables_state(backup);
mysql_proc_table_exists= 0;
DBUG_RETURN(0);
}
@@ -130,15 +134,13 @@ static TABLE *open_proc_table_for_read(THD *thd)
table->reginfo.lock_type= TL_READ;
/*
- If we have other tables opened, we have to ensure we are not blocked
- by a flush tables or global read lock, as this could lead to a deadlock
+ We have to ensure we are not blocked by a flush tables, as this
+ could lead to a deadlock if we have other tables opened.
*/
if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
- old_open_tables ?
- (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
- MYSQL_LOCK_IGNORE_FLUSH) : 0)))
+ MYSQL_LOCK_IGNORE_FLUSH)))
{
- close_proc_table(thd);
+ close_proc_table(thd, backup);
DBUG_RETURN(0);
}
DBUG_RETURN(table);
@@ -271,12 +273,13 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
char buff[65];
String str(buff, sizeof(buff), &my_charset_bin);
ulong sql_mode;
+ Open_tables_state open_tables_state_backup;
DBUG_ENTER("db_find_routine");
DBUG_PRINT("enter", ("type: %d name: %*s",
type, name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors
- if (!(table= open_proc_table_for_read(thd)))
+ if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
@@ -371,7 +374,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
chistics.comment.str= ptr;
chistics.comment.length= length;
- close_proc_table(thd);
+ close_proc_table(thd, &open_tables_state_backup);
table= 0;
{
@@ -424,7 +427,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
LEX *newlex= thd->lex;
sp_head *sp= newlex->sphead;
- if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
goto done;
if (sp)
{
@@ -435,7 +438,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
else
{
- if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
goto done;
*sphp= thd->lex->sphead;
(*sphp)->set_info((char *)definer, (uint)strlen(definer),
@@ -449,7 +452,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
done:
if (table)
- close_proc_table(thd);
+ close_proc_table(thd, &open_tables_state_backup);
DBUG_RETURN(ret);
}
@@ -591,7 +594,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
done:
close_thread_tables(thd);
if (dbchanged)
- (void)sp_change_db(thd, olddb, 1);
+ (void)mysql_change_db(thd, olddb, 1);
DBUG_RETURN(ret);
}
@@ -786,6 +789,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);
for (used_field= &used_fields[0];
used_field->field_name;
@@ -795,7 +799,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
"mysql", "proc",
used_field->field_name);
if (!field ||
- !(used_field->field= find_field_in_tables(thd, field, &tables,
+ !(used_field->field= find_field_in_tables(thd, field, &tables, NULL,
0, REPORT_ALL_ERRORS, 1,
TRUE)))
{
@@ -986,13 +990,11 @@ int
sp_drop_procedure(THD *thd, sp_name *name)
{
int ret;
- bool found;
DBUG_ENTER("sp_drop_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1002,13 +1004,11 @@ int
sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
- bool found;
DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1099,13 +1099,11 @@ int
sp_drop_function(THD *thd, sp_name *name)
{
int ret;
- bool found;
DBUG_ENTER("sp_drop_function");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_func_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1115,13 +1113,11 @@ int
sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
{
int ret;
- bool found;
DBUG_ENTER("sp_update_procedure");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- found= sp_cache_remove(&thd->sp_func_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
- if (!found && !ret)
+ if (!ret)
sp_cache_invalidate();
DBUG_RETURN(ret);
}
@@ -1617,112 +1613,10 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
}
else
{
- int ret= sp_change_db(thd, newdb, no_access_check);
+ int ret= mysql_change_db(thd, newdb, no_access_check);
if (! ret)
*dbchangedp= TRUE;
DBUG_RETURN(ret);
}
}
-
-/*
- Change database.
-
- SYNOPSIS
- sp_change_db()
- thd Thread handler
- name Database name
- empty_is_ok True= it's ok with "" as name
- no_access_check True= don't do access check
-
- DESCRIPTION
- This is the same as mysql_change_db(), but with some extra
- arguments for Stored Procedure usage; doing implicit "use"
- when executing an SP in a different database.
- We also use different error routines, since this might be
- invoked from a function when executing a query or statement.
- Note: We would have prefered to reuse mysql_change_db(), but
- the error handling in particular made that too awkward, so
- we (reluctantly) have a "copy" here.
-
- RETURN VALUES
- 0 ok
- 1 error
-*/
-
-int
-sp_change_db(THD *thd, char *name, bool no_access_check)
-{
- int length, db_length;
- char *dbname=my_strdup((char*) name,MYF(MY_WME));
- char path[FN_REFLEN];
- HA_CREATE_INFO create;
- DBUG_ENTER("sp_change_db");
- DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
-
- db_length= (!dbname ? 0 : strip_sp(dbname));
- if (dbname && db_length)
- {
- if ((db_length > NAME_LEN) || check_db_name(dbname))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
- x_free(dbname);
- DBUG_RETURN(1);
- }
- }
-
- if (dbname && db_length)
- {
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (! no_access_check)
- {
- ulong db_access;
-
- if (test_all_bits(thd->master_access,DB_ACLS))
- db_access=DB_ACLS;
- else
- db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
- thd->master_access);
- if (!(db_access & DB_ACLS) &&
- (!grant_option || check_grant_db(thd,dbname)))
- {
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user,
- thd->priv_host,
- dbname);
- mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- thd->priv_user,
- thd->priv_host,
- dbname);
- my_free(dbname,MYF(0));
- DBUG_RETURN(1);
- }
- }
-#endif
- (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
- length=unpack_dirname(path,path); // Convert if not unix
- if (length && path[length-1] == FN_LIBCHAR)
- path[length-1]=0; // remove ending '\'
- if (access(path,F_OK))
- {
- my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
- my_free(dbname,MYF(0));
- DBUG_RETURN(1);
- }
- }
-
- x_free(thd->db);
- thd->db=dbname; // THD::~THD will free this
- thd->db_length=db_length;
-
- if (dbname && db_length)
- {
- strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
- }
- DBUG_RETURN(0);
-}
diff --git a/sql/sp.h b/sql/sp.h
index 58244c34761..c278da863e0 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -94,6 +94,13 @@ void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
+/*
+ Routines which allow open/lock and close mysql.proc table even when
+ we already have some tables open and locked.
+*/
+TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
+void close_proc_table(THD *thd, Open_tables_state *backup);
+
//
// Utilities...
//
@@ -105,8 +112,4 @@ int
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
bool no_access_check, bool *dbchangedp);
-// Like mysql_change_db() but handles empty db name and the send_ok() problem.
-int
-sp_change_db(THD *thd, char *db, bool no_access_check);
-
#endif /* _SP_H_ */
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index c8f0ed6ba2d..495f969eeac 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -22,16 +22,80 @@
#include "sp_head.h"
static pthread_mutex_t Cversion_lock;
-static ulong Cversion = 0;
+static ulong volatile Cversion= 0;
-void
-sp_cache_init()
+
+/*
+ Cache of stored routines.
+*/
+
+class sp_cache
+{
+public:
+ ulong version;
+
+ sp_cache();
+ ~sp_cache();
+
+ inline void insert(sp_head *sp)
+ {
+ /* TODO: why don't we check return value? */
+ my_hash_insert(&m_hashtable, (const byte *)sp);
+ }
+
+ inline sp_head *lookup(char *name, uint namelen)
+ {
+ return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
+ }
+
+#ifdef NOT_USED
+ inline bool remove(char *name, uint namelen)
+ {
+ sp_head *sp= lookup(name, namelen);
+ if (sp)
+ {
+ hash_delete(&m_hashtable, (byte *)sp);
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif
+
+ inline void remove_all()
+ {
+ cleanup();
+ init();
+ }
+
+private:
+ void init();
+ void cleanup();
+
+ /* All routines in this cache */
+ HASH m_hashtable;
+}; // class sp_cache
+
+
+/* Initialize the SP caching once at startup */
+
+void sp_cache_init()
{
pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST);
}
-void
-sp_cache_clear(sp_cache **cp)
+
+/*
+ Clear the cache *cp and set *cp to NULL.
+
+ SYNOPSIS
+ sp_cache_clear()
+ cp Pointer to cache to clear
+
+ NOTE
+ This function doesn't invalidate other caches.
+*/
+
+void sp_cache_clear(sp_cache **cp)
{
sp_cache *c= *cp;
@@ -42,114 +106,145 @@ sp_cache_clear(sp_cache **cp)
}
}
-void
-sp_cache_insert(sp_cache **cp, sp_head *sp)
-{
- sp_cache *c= *cp;
- if (! c)
- c= new sp_cache();
- if (c)
- {
- ulong v;
+/*
+ Insert a routine into the cache.
- pthread_mutex_lock(&Cversion_lock); // LOCK
- v= Cversion;
- pthread_mutex_unlock(&Cversion_lock); // UNLOCK
+ SYNOPSIS
+ sp_cache_insert()
+ cp The cache to put routine into
+ sp Routine to insert.
+
+ TODO: Perhaps it will be more straightforward if in case we returned an
+ error from this function when we couldn't allocate sp_cache. (right
+ now failure to put routine into cache will cause a 'SP not found'
+ error to be reported at some later time)
+*/
- if (c->version < v)
- {
- if (*cp)
- c->remove_all();
- c->version= v;
- }
- c->insert(sp);
- if (*cp == NULL)
- *cp= c;
+void sp_cache_insert(sp_cache **cp, sp_head *sp)
+{
+ sp_cache *c;
+ ulong v;
+
+ if (!(c= *cp))
+ {
+ if (!(c= new sp_cache()))
+ return; // End of memory error
+ c->version= Cversion; // No need to lock when reading long variable
}
+ DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length,
+ sp->m_qname.str));
+ c->insert(sp);
+ *cp= c; // Update *cp if it was NULL
}
-sp_head *
-sp_cache_lookup(sp_cache **cp, sp_name *name)
+
+/*
+ Look up a routine in the cache.
+ SYNOPSIS
+ sp_cache_lookup()
+ cp Cache to look into
+ name Name of rutine to find
+
+ NOTE
+ An obsolete (but not more obsolete then since last
+ sp_cache_flush_obsolete call) routine may be returned.
+
+ RETURN
+ The routine or
+ NULL if the routine not found.
+*/
+
+sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name)
{
- ulong v;
sp_cache *c= *cp;
-
if (! c)
return NULL;
+ return c->lookup(name->m_qname.str, name->m_qname.length);
+}
- pthread_mutex_lock(&Cversion_lock); // LOCK
- v= Cversion;
- pthread_mutex_unlock(&Cversion_lock); // UNLOCK
- if (c->version < v)
- {
- c->remove_all();
- c->version= v;
- return NULL;
- }
- return c->lookup(name->m_qname.str, name->m_qname.length);
+/*
+ Invalidate all routines in all caches.
+
+ SYNOPSIS
+ sp_cache_invalidate()
+
+ NOTE
+ This is called when a VIEW definition is modifed. We can't destroy sp_head
+ objects here as one may modify VIEW definitions from prelocking-free SPs.
+*/
+
+void sp_cache_invalidate()
+{
+ DBUG_PRINT("info",("sp_cache: invalidating"));
+ thread_safe_increment(Cversion, &Cversion_lock);
}
-bool
-sp_cache_remove(sp_cache **cp, sp_name *name)
+
+/*
+ Remove out-of-date SPs from the cache.
+
+ SYNOPSIS
+ sp_cache_flush_obsolete()
+ cp Cache to flush
+
+ NOTE
+ This invalidates pointers to sp_head objects this thread uses.
+ In practice that means 'dont call this function when inside SP'.
+*/
+
+void sp_cache_flush_obsolete(sp_cache **cp)
{
sp_cache *c= *cp;
- bool found= FALSE;
-
if (c)
{
ulong v;
-
- pthread_mutex_lock(&Cversion_lock); // LOCK
- v= Cversion++;
- pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-
+ v= Cversion; // No need to lock when reading long variable
if (c->version < v)
+ {
+ DBUG_PRINT("info",("sp_cache: deleting all functions"));
+ /* We need to delete all elements. */
c->remove_all();
- else
- found= c->remove(name->m_qname.str, name->m_qname.length);
- c->version= v+1;
+ c->version= v;
+ }
}
- return found;
}
-void
-sp_cache_invalidate()
-{
- pthread_mutex_lock(&Cversion_lock); // LOCK
- Cversion++;
- pthread_mutex_unlock(&Cversion_lock); // UNLOCK
-}
-static byte *
-hash_get_key_for_sp_head(const byte *ptr, uint *plen,
+/*************************************************************************
+ Internal functions
+ *************************************************************************/
+
+static byte *hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first)
{
sp_head *sp= (sp_head *)ptr;
-
*plen= sp->m_qname.length;
return (byte*) sp->m_qname.str;
}
+
static void
hash_free_sp_head(void *p)
{
sp_head *sp= (sp_head *)p;
-
delete sp;
}
+
sp_cache::sp_cache()
{
init();
}
+
sp_cache::~sp_cache()
{
hash_free(&m_hashtable);
}
+
void
sp_cache::init()
{
@@ -158,6 +253,7 @@ sp_cache::init()
version= 0;
}
+
void
sp_cache::cleanup()
{
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
index 14b2db97f5f..1021d17b9e2 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -25,94 +25,39 @@
/*
Stored procedures/functions cache. This is used as follows:
* Each thread has its own cache.
- * Each sp_head object is put into its thread cache before it is used, and
+ * Each sp_head object is put into its thread cache before it is used, and
then remains in the cache until deleted.
*/
class sp_head;
class sp_cache;
-/* Initialize the SP caching once at startup */
-void sp_cache_init();
+/*
+ Cache usage scenarios:
+ 1. Application-wide init:
+ sp_cache_init();
+
+ 2. SP execution in thread:
+ 2.1 While holding sp_head* pointers:
+
+ // look up a routine in the cache (no checks if it is up to date or not)
+ sp_cache_lookup();
+
+ sp_cache_insert();
+ sp_cache_invalidate();
+
+ 2.2 When not holding any sp_head* pointers:
+ sp_cache_flush_obsolete();
+
+ 3. Before thread exit:
+ sp_cache_clear();
+*/
-/* Clear the cache *cp and set *cp to NULL */
+void sp_cache_init();
void sp_cache_clear(sp_cache **cp);
-
-/* Insert an SP into cache. If 'cp' points to NULL, it's set to a new cache */
void sp_cache_insert(sp_cache **cp, sp_head *sp);
-
-/* Lookup an SP in cache */
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
-
-/*
- Remove an SP from cache, and also bump the Cversion number so all other
- caches are invalidated.
- Returns true if something was removed.
-*/
-bool sp_cache_remove(sp_cache **cp, sp_name *name);
-
-/* Invalidate all existing SP caches by bumping Cversion number. */
void sp_cache_invalidate();
-
-
-/*
- *
- * The cache class. Don't use this directly, use the C API above
- *
- */
-
-class sp_cache
-{
-public:
-
- ulong version;
-
- sp_cache();
-
- ~sp_cache();
-
- void
- init();
-
- void
- cleanup();
-
- inline void
- insert(sp_head *sp)
- {
- my_hash_insert(&m_hashtable, (const byte *)sp);
- }
-
- inline sp_head *
- lookup(char *name, uint namelen)
- {
- return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
- }
-
- inline bool
- remove(char *name, uint namelen)
- {
- sp_head *sp= lookup(name, namelen);
-
- if (sp)
- {
- hash_delete(&m_hashtable, (byte *)sp);
- return TRUE;
- }
- return FALSE;
- }
-
- inline void
- remove_all()
- {
- cleanup();
- init();
- }
-
-private:
-
- HASH m_hashtable;
-
-}; // class sp_cache
+void sp_cache_flush_obsolete(sp_cache **cp);
#endif /* _SP_CACHE_H_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 3a386356335..dfc91f5a3f4 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -126,16 +126,48 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
}
-/* Evaluate a (presumed) func item. Always returns an item, the parameter
-** if nothing else.
+/* Macro to switch arena in sp_eval_func_item */
+#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) \
+ do \
+ { \
+ if (condition) \
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena, \
+ backup_arena); \
+ new_command; \
+ if (condition) \
+ thd->restore_backup_item_arena(thd->spcont->callers_arena, \
+ &backup_current_arena); \
+ } while(0)
+
+/*
+ Evaluate an item and store it in the returned item
+
+ SYNOPSIS
+ sp_eval_func_item()
+ name - current thread object
+ it_addr - pointer to the item to evaluate
+ type - type of the item we evaluating
+ reuse - used if we would like to reuse existing item
+ instead of allocation of the new one
+ use_callers_arena - TRUE if we want to use caller's arena
+ rather then current one.
+ DESCRIPTION
+ We use this function to evaluate result for stored functions
+ and stored procedure parameters. It is also used to evaluate and
+ (re) allocate variables.
+
+ RETURN VALUES
+ Evaluated item is returned
*/
+
Item *
sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
- Item *reuse)
+ Item *reuse, bool use_callers_arena)
{
DBUG_ENTER("sp_eval_func_item");
Item *it= sp_prepare_func_item(thd, it_addr);
uint rsize;
+ Query_arena backup_current_arena;
DBUG_PRINT("info", ("type: %d", type));
if (!it)
@@ -143,93 +175,96 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
DBUG_RETURN(NULL);
}
- /* QQ How do we do this? Is there some better way? */
- if (type == MYSQL_TYPE_NULL)
- it= new(reuse, &rsize) Item_null();
- else
+ switch (sp_map_result_type(type)) {
+ case INT_RESULT:
{
- switch (sp_map_result_type(type)) {
- case INT_RESULT:
- {
- longlong i= it->val_int();
+ longlong i= it->val_int();
- if (it->null_value)
- {
- DBUG_PRINT("info", ("INT_RESULT: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- DBUG_PRINT("info", ("INT_RESULT: %d", i));
- it= new(reuse, &rsize) Item_int(i);
- }
- break;
- }
- case REAL_RESULT:
- {
- double d= it->val_real();
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("INT_RESULT: null"));
+ goto return_null_item;
+ }
+ DBUG_PRINT("info", ("INT_RESULT: %d", i));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
+ use_callers_arena, &backup_current_arena);
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double d= it->val_real();
+ uint8 decimals;
+ uint32 max_length;
- if (it->null_value)
- {
- DBUG_PRINT("info", ("REAL_RESULT: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- /* There's some difference between Item::new_item() and the
- * constructor; the former crashes, the latter works... weird. */
- uint8 decimals= it->decimals;
- uint32 max_length= it->max_length;
- DBUG_PRINT("info", ("REAL_RESULT: %g", d));
- it= new(reuse, &rsize) Item_float(d);
- it->decimals= decimals;
- it->max_length= max_length;
- }
- break;
- }
- case DECIMAL_RESULT:
- {
- my_decimal value, *val= it->val_decimal(&value);
- if (it->null_value)
- it= new(reuse, &rsize) Item_null();
- else
- it= new(reuse, &rsize) Item_decimal(val);
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("REAL_RESULT: null"));
+ goto return_null_item;
+ }
+
+ /*
+ There's some difference between Item::new_item() and the
+ constructor; the former crashes, the latter works... weird.
+ */
+ decimals= it->decimals;
+ max_length= it->max_length;
+ DBUG_PRINT("info", ("REAL_RESULT: %g", d));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
+ use_callers_arena, &backup_current_arena);
+ it->decimals= decimals;
+ it->max_length= max_length;
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= it->val_decimal(&value);
+ if (it->null_value)
+ goto return_null_item;
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
+ use_callers_arena, &backup_current_arena);
#ifndef DBUG_OFF
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
- DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
+ {
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ DBUG_PRINT("info", ("DECIMAL_RESULT: %s",
+ dbug_decimal_as_string(dbug_buff, val)));
+ }
#endif
- break;
- }
- case STRING_RESULT:
- {
- char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer, sizeof(buffer), it->collation.collation);
- String *s= it->val_str(&tmp);
+ break;
+ }
+ case STRING_RESULT:
+ {
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer, sizeof(buffer), it->collation.collation);
+ String *s= it->val_str(&tmp);
- if (it->null_value)
- {
- DBUG_PRINT("info", ("default result: null"));
- it= new(reuse, &rsize) Item_null();
- }
- else
- {
- DBUG_PRINT("info",("default result: %*s",
- s->length(), s->c_ptr_quick()));
- it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(),
- s->length()),
- s->length(),
- it->collation.collation);
- }
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
+ if (type == MYSQL_TYPE_NULL || it->null_value)
+ {
+ DBUG_PRINT("info", ("STRING_RESULT: null"));
+ goto return_null_item;
}
+ DBUG_PRINT("info",("STRING_RESULT: %*s",
+ s->length(), s->c_ptr_quick()));
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
+ Item_string(thd->strmake(s->ptr(),
+ s->length()), s->length(),
+ it->collation.collation),
+ use_callers_arena, &backup_current_arena);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
it->rsize= rsize;
DBUG_RETURN(it);
+
+return_null_item:
+ CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
+ use_callers_arena, &backup_current_arena);
+ it->rsize= rsize;
+
+ DBUG_RETURN(it);
}
@@ -534,34 +569,22 @@ sp_head::destroy()
/*
- * This is only used for result fields from functions (both during
- * fix_length_and_dec() and evaluation).
- *
- * Since the current mem_root during a will be freed and the result
- * field will be used by the caller, we have to put it in the caller's
- * or main mem_root.
- */
+ This is only used for result fields from functions (both during
+ fix_length_and_dec() and evaluation).
+*/
+
Field *
sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
{
Field *field;
- MEM_ROOT *tmp_mem_root;
- THD *thd;
DBUG_ENTER("sp_head::make_field");
- thd= current_thd;
- tmp_mem_root= thd->mem_root;
- if (thd->spcont && thd->spcont->callers_mem_root)
- thd->mem_root= thd->spcont->callers_mem_root;
- else
- thd->mem_root= &thd->main_mem_root;
field= ::make_field((char *)0,
!m_returns_len ? max_length : m_returns_len,
(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
(enum Field::geometry_type)0, Field::NONE,
m_returns_typelib,
name ? name : (const char *)m_name.str, dummy);
- thd->mem_root= tmp_mem_root;
DBUG_RETURN(field);
}
@@ -576,12 +599,20 @@ sp_head::execute(THD *thd)
uint ip= 0;
ulong save_sql_mode;
Query_arena *old_arena;
+ /* per-instruction arena */
+ MEM_ROOT execute_mem_root;
+ Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
+ execute_backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
LEX *old_lex;
Item_change_list old_change_list;
String old_packet;
+ /* init per-instruction memroot */
+ init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+
+
/* Use some extra margin for possible SP recursion and functions */
if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb))
{
@@ -650,6 +681,18 @@ sp_head::execute(THD *thd)
*/
old_packet.swap(thd->packet);
+ /*
+ Switch to per-instruction arena here. We can do it since we cleanup
+ arena after every instruction.
+ */
+ thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena);
+
+ /*
+ Save callers arena in order to store instruction results and out
+ parameters in it later during sp_eval_func_item()
+ */
+ thd->spcont->callers_arena= &execute_backup_arena;
+
do
{
sp_instr *i;
@@ -659,7 +702,9 @@ sp_head::execute(THD *thd)
if (i == NULL)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
- thd->set_time(); // Make current_time() et al work
+ /* Don't change NOW() in FUNCTION or TRIGGER */
+ if (!thd->in_sub_stmt)
+ thd->set_time(); // Make current_time() et al work
/*
We have to set thd->current_arena before executing the instruction
to store in the instruction free_list all new items, created
@@ -668,6 +713,7 @@ sp_head::execute(THD *thd)
*/
thd->current_arena= i;
ret= i->execute(thd, &ip);
+
/*
If this SP instruction have sent eof, it has caused no_send_error to be
set. Clear it back to allow the next instruction to send error. (multi-
@@ -678,23 +724,30 @@ sp_head::execute(THD *thd)
cleanup_items(i->free_list);
i->state= Query_arena::EXECUTED;
- // Check if an exception has occurred and a handler has been found
- // Note: We havo to check even if ret==0, since warnings (and some
- // errors don't return a non-zero value.
- // We also have to check even if thd->killed != 0, since some
- // errors return with this even when a handler has been found
- // (e.g. "bad data").
+ /* we should cleanup free_list and memroot, used by instruction */
+ thd->free_items();
+ free_root(&execute_mem_root, MYF(0));
+
+ /*
+ Check if an exception has occurred and a handler has been found
+ Note: We havo to check even if ret==0, since warnings (and some
+ errors don't return a non-zero value.
+ We also have to check even if thd->killed != 0, since some
+ errors return with this even when a handler has been found
+ (e.g. "bad data").
+ */
if (ctx)
{
uint hf;
- switch (ctx->found_handler(&hip, &hf))
- {
+ switch (ctx->found_handler(&hip, &hf)) {
case SP_HANDLER_NONE:
break;
case SP_HANDLER_CONTINUE:
- ctx->save_variables(hf);
- ctx->push_hstack(ip);
+ thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena);
+ ctx->save_variables(hf);
+ thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena);
+ ctx->push_hstack(ip);
// Fall through
default:
ip= hip;
@@ -708,6 +761,9 @@ sp_head::execute(THD *thd)
}
} while (ret == 0 && !thd->killed);
+ thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena);
+
+
/* Restore all saved */
old_packet.swap(thd->packet);
DBUG_ASSERT(thd->change_list.is_empty());
@@ -734,7 +790,7 @@ sp_head::execute(THD *thd)
if (dbchanged)
{
if (! thd->killed)
- ret= sp_change_db(thd, olddb, 0);
+ ret= mysql_change_db(thd, olddb, 0);
}
m_is_invoked= FALSE;
DBUG_RETURN(ret);
@@ -753,68 +809,61 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
uint i;
- int ret;
- MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
+ Item_null *nit;
+ int ret= -1; // Assume error
if (argcount != params)
{
- // Need to use my_printf_error here, or it will not terminate the
- // invoking query properly.
+ /*
+ Need to use my_error here, or it will not terminate the
+ invoking query properly.
+ */
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
"FUNCTION", m_qname.str, params, argcount);
- DBUG_RETURN(-1);
+ goto end;
}
- init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
-
// QQ Should have some error checking here? (types, etc...)
- nctx= new sp_rcontext(csize, hmax, cmax);
- nctx->callers_mem_root= thd->mem_root;
+ if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+ goto end;
for (i= 0 ; i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
- Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL);
+ Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
- if (it)
- nctx->push_item(it);
- else
- {
- DBUG_RETURN(-1);
- }
+ if (!it)
+ goto end; // EOM error
+ nctx->push_item(it);
}
- // The rest of the frame are local variables which are all IN.
- // Default all variables to null (those with default clauses will
- // be set by an set instruction).
+
+ /*
+ The rest of the frame are local variables which are all IN.
+ Default all variables to null (those with default clauses will
+ be set by an set instruction).
+ */
+
+ nit= NULL; // Re-use this, and only create if needed
+ for (; i < csize ; i++)
{
- Item_null *nit= NULL; // Re-use this, and only create if needed
- for (; i < csize ; i++)
+ if (! nit)
{
- if (! nit)
- nit= new Item_null();
- nctx->push_item(nit);
+ if (!(nit= new Item_null()))
+ DBUG_RETURN(-1);
}
+ nctx->push_item(nit);
}
thd->spcont= nctx;
- thd->set_n_backup_item_arena(&call_arena, &backup_arena);
- /* mem_root was moved to backup_arena */
- DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root);
ret= execute(thd);
- // Partially restore context now.
- // We still need the call mem root and free list for processing
- // of the result.
- thd->restore_backup_item_arena(&call_arena, &backup_arena);
-
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
/* We need result only in function but not in trigger */
Item *it= nctx->get_result();
if (it)
- *resp= sp_eval_func_item(thd, &it, m_returns, NULL);
+ *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
else
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
@@ -823,17 +872,15 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ delete nctx; // Doesn't do anything
thd->spcont= octx;
- // Now get rid of the rest of the callee context
- call_arena.free_items();
- free_root(&call_mem_root, MYF(0));
-
+end:
DBUG_RETURN(ret);
}
-static Item_func_get_user_var *
-item_is_user_var(Item *it)
+
+static Item_func_get_user_var *item_is_user_var(Item *it)
{
if (it->type() == Item::FUNC_ITEM)
{
@@ -845,21 +892,18 @@ item_is_user_var(Item *it)
return NULL;
}
-int
-sp_head::execute_procedure(THD *thd, List<Item> *args)
+
+int sp_head::execute_procedure(THD *thd, List<Item> *args)
{
- DBUG_ENTER("sp_head::execute_procedure");
- DBUG_PRINT("info", ("procedure %s", m_name.str));
int ret= 0;
uint csize = m_pcont->max_pvars();
uint params = m_pcont->current_pvars();
uint hmax = m_pcont->max_handlers();
uint cmax = m_pcont->max_cursors();
- sp_rcontext *octx = thd->spcont;
+ sp_rcontext *save_spcont, *octx;
sp_rcontext *nctx = NULL;
- my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
- MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
+ DBUG_ENTER("sp_head::execute_procedure");
+ DBUG_PRINT("info", ("procedure %s", m_name.str));
if (args->elements != params)
{
@@ -868,7 +912,22 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
DBUG_RETURN(-1);
}
- init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+ save_spcont= octx= thd->spcont;
+ if (! octx)
+ { // Create a temporary old context
+ if (!(octx= new sp_rcontext(csize, hmax, cmax)))
+ DBUG_RETURN(-1);
+ thd->spcont= octx;
+
+ /* set callers_arena to thd, for upper-level function to work */
+ thd->spcont->callers_arena= thd;
+ }
+
+ if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
+ {
+ thd->spcont= save_spcont;
+ DBUG_RETURN(-1);
+ }
if (csize > 0 || hmax > 0 || cmax > 0)
{
@@ -877,13 +936,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
List_iterator<Item> li(*args);
Item *it;
- nctx= new sp_rcontext(csize, hmax, cmax);
- if (! octx)
- { // Create a temporary old context
- octx= new sp_rcontext(csize, hmax, cmax);
- tmp_octx= TRUE;
- }
-
/* Evaluate SP arguments (i.e. get the values passed as parameters) */
// QQ: Should do type checking?
DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
@@ -905,20 +957,25 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (pvar->mode == sp_param_out)
{
if (! nit)
- nit= new Item_null();
+ {
+ if (!(nit= new Item_null()))
+ {
+ ret= -1;
+ break;
+ }
+ }
nctx->push_item(nit); // OUT
}
else
{
- Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL);
+ Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
- if (it2)
- nctx->push_item(it2); // IN or INOUT
- else
+ if (!it2)
{
ret= -1; // Eval failed
break;
}
+ nctx->push_item(it2); // IN or INOUT
}
}
}
@@ -929,35 +986,50 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
we'll leave it here.
*/
if (!thd->in_sub_stmt)
- close_thread_tables(thd, 0, 0, 0);
+ close_thread_tables(thd, 0, 0);
DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
- // The rest of the frame are local variables which are all IN.
- // Default all variables to null (those with default clauses will
- // be set by an set instruction).
+ /*
+ The rest of the frame are local variables which are all IN.
+ Default all variables to null (those with default clauses will
+ be set by an set instruction).
+ */
for (; i < csize ; i++)
{
if (! nit)
- nit= new Item_null();
+ {
+ if (!(nit= new Item_null()))
+ {
+ ret= -1;
+ break;
+ }
+ }
nctx->push_item(nit);
}
- thd->spcont= nctx;
}
+ thd->spcont= nctx;
+
if (! ret)
- {
- thd->set_n_backup_item_arena(&call_arena, &backup_arena);
ret= execute(thd);
- thd->restore_backup_item_arena(&call_arena, &backup_arena);
- }
+
+ /*
+ In the case when we weren't able to employ reuse mechanism for
+ OUT/INOUT paranmeters, we should reallocate memory. This
+ allocation should be done on the arena which will live through
+ all execution of calling routine.
+ */
+ thd->spcont->callers_arena= octx->callers_arena;
if (!ret && csize > 0)
{
List_iterator<Item> li(*args);
Item *it;
- // Copy back all OUT or INOUT values to the previous frame, or
- // set global user variables
+ /*
+ Copy back all OUT or INOUT values to the previous frame, or
+ set global user variables
+ */
for (uint i = 0 ; (it= li++) && i < params ; i++)
{
sp_pvar_t *pvar= m_pcont->find_pvar(i);
@@ -972,12 +1044,20 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
Item *val= nctx->get_item(i);
Item *orig= octx->get_item(offset);
Item *o_item_next;
- Item *o_free_list= thd->free_list;
+ /* we'll use callers_arena in sp_eval_func_item */
+ Item *o_free_list= thd->spcont->callers_arena->free_list;
+
LINT_INIT(o_item_next);
if (orig)
o_item_next= orig->next;
- copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy
+
+ /*
+ We might need to allocate new item if we weren't able to
+ employ reuse mechanism. Then we should do it on the callers arena.
+ */
+ copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy
+
if (!copy)
{
ret= -1;
@@ -987,9 +1067,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
octx->set_item(offset, copy);
if (orig && copy == orig)
{
- // A reused item slot, where the constructor put it in the
- // free_list, so we have to restore the list.
- thd->free_list= o_free_list;
+ /*
+ A reused item slot, where the constructor put it in the
+ free_list, so we have to restore the list.
+ */
+ thd->spcont->callers_arena->free_list= o_free_list;
copy->next= o_item_next;
}
}
@@ -1017,16 +1099,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
}
- if (tmp_octx)
- octx= NULL;
- if (nctx)
- nctx->pop_all_cursors(); // To avoid memory leaks after an error
- thd->spcont= octx;
+ if (!save_spcont)
+ delete octx; // Does nothing
- // Now get rid of the rest of the callee context
- call_arena.free_items();
- thd->lex->unit.cleanup();
- free_root(&call_mem_root, MYF(0));
+ nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ delete nctx; // Does nothing
+ thd->spcont= save_spcont;
DBUG_RETURN(ret);
}
@@ -1420,8 +1498,6 @@ sp_head::opt_mark(uint ip)
ip= i->opt_mark(this);
}
-// ------------------------------------------------------------------
-
/*
Prepare LEX and thread for execution of instruction, if requested open
@@ -1513,6 +1589,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
thd->proc_info="closing tables";
close_thread_tables(thd);
+ thd->proc_info= 0;
if (m_lex->query_tables_own_last)
{
@@ -1549,9 +1626,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
}
-//
-// sp_instr
-//
+/*
+ sp_instr class functions
+*/
+
int sp_instr::exec_core(THD *thd, uint *nextp)
{
DBUG_ASSERT(0);
@@ -1559,9 +1637,10 @@ int sp_instr::exec_core(THD *thd, uint *nextp)
}
-//
-// sp_instr_stmt
-//
+/*
+ sp_instr_stmt class functions
+*/
+
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
@@ -1606,9 +1685,11 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp)
return res;
}
-//
-// sp_instr_set
-//
+
+/*
+ sp_instr_set class functions
+*/
+
int
sp_instr_set::execute(THD *thd, uint *nextp)
{
@@ -1618,6 +1699,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}
+
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
@@ -1638,9 +1720,10 @@ sp_instr_set::print(String *str)
}
-//
-// sp_instr_set_trigger_field
-//
+/*
+ sp_instr_set_trigger_field class functions
+*/
+
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
@@ -1671,9 +1754,11 @@ sp_instr_set_trigger_field::print(String *str)
value->print(str);
}
-//
-// sp_instr_jump
-//
+
+/*
+ sp_instr_jump class functions
+*/
+
int
sp_instr_jump::execute(THD *thd, uint *nextp)
{
@@ -1732,9 +1817,10 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
m_ip= dst;
}
-//
-// sp_instr_jump_if
-//
+
+/*
+ sp_instr_jump_if class functions
+*/
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
@@ -1790,9 +1876,11 @@ sp_instr_jump_if::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_jump_if_not
-//
+
+/*
+ sp_instr_jump_if_not class functions
+*/
+
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
@@ -1823,6 +1911,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
return res;
}
+
void
sp_instr_jump_if_not::print(String *str)
{
@@ -1833,6 +1922,7 @@ sp_instr_jump_if_not::print(String *str)
m_expr->print(str);
}
+
uint
sp_instr_jump_if_not::opt_mark(sp_head *sp)
{
@@ -1848,9 +1938,10 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_freturn
-//
+
+/*
+ sp_instr_freturn class functions
+*/
int
sp_instr_freturn::execute(THD *thd, uint *nextp)
@@ -1866,7 +1957,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_eval_func_item(thd, &m_value, m_type, NULL);
+ it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
if (! it)
res= -1;
else
@@ -1889,9 +1980,10 @@ sp_instr_freturn::print(String *str)
m_value->print(str);
}
-//
-// sp_instr_hpush_jump
-//
+/*
+ sp_instr_hpush_jump class functions
+*/
+
int
sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
{
@@ -1900,7 +1992,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
sp_cond_type_t *p;
while ((p= li++))
- thd->spcont->push_handler(p, m_handler, m_type, m_frame);
+ thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
*nextp= m_dest;
DBUG_RETURN(0);
@@ -1917,7 +2009,7 @@ sp_instr_hpush_jump::print(String *str)
str->append(" f=");
str->qs_append(m_frame);
str->append(" h=");
- str->qs_append(m_handler);
+ str->qs_append(m_ip+1);
}
uint
@@ -1935,9 +2027,11 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
return m_ip+1;
}
-//
-// sp_instr_hpop
-//
+
+/*
+ sp_instr_hpop class functions
+*/
+
int
sp_instr_hpop::execute(THD *thd, uint *nextp)
{
@@ -1962,9 +2056,10 @@ sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx)
}
-//
-// sp_instr_hreturn
-//
+/*
+ sp_instr_hreturn class functions
+*/
+
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
@@ -1980,6 +2075,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
DBUG_RETURN(0);
}
+
void
sp_instr_hreturn::print(String *str)
{
@@ -1990,6 +2086,7 @@ sp_instr_hreturn::print(String *str)
str->qs_append(m_dest);
}
+
uint
sp_instr_hreturn::opt_mark(sp_head *sp)
{
@@ -2003,27 +2100,45 @@ sp_instr_hreturn::opt_mark(sp_head *sp)
}
-//
-// sp_instr_cpush
-//
+/*
+ sp_instr_cpush class functions
+*/
+
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
+ Query_arena backup_current_arena;
DBUG_ENTER("sp_instr_cpush::execute");
+
+ /*
+ We should create cursors in the callers arena, as
+ it could be (and usually is) used in several instructions.
+ */
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+
thd->spcont->push_cursor(&m_lex_keeper, this);
+
+ thd->restore_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+
*nextp= m_ip+1;
+
DBUG_RETURN(0);
}
+
void
sp_instr_cpush::print(String *str)
{
str->append("cpush");
}
-//
-// sp_instr_cpop
-//
+
+/*
+ sp_instr_cpop class functions
+*/
+
int
sp_instr_cpop::execute(THD *thd, uint *nextp)
{
@@ -2033,6 +2148,7 @@ sp_instr_cpop::execute(THD *thd, uint *nextp)
DBUG_RETURN(0);
}
+
void
sp_instr_cpop::print(String *str)
{
@@ -2047,9 +2163,11 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
m_count= m_ctx->diff_cursors(dst_ctx);
}
-//
-// sp_instr_copen
-//
+
+/*
+ sp_instr_copen class functions
+*/
+
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
@@ -2117,9 +2235,11 @@ sp_instr_copen::print(String *str)
str->qs_append(m_cursor);
}
-//
-// sp_instr_cclose
-//
+
+/*
+ sp_instr_cclose class functions
+*/
+
int
sp_instr_cclose::execute(THD *thd, uint *nextp)
{
@@ -2135,6 +2255,7 @@ sp_instr_cclose::execute(THD *thd, uint *nextp)
DBUG_RETURN(res);
}
+
void
sp_instr_cclose::print(String *str)
{
@@ -2143,24 +2264,35 @@ sp_instr_cclose::print(String *str)
str->qs_append(m_cursor);
}
-//
-// sp_instr_cfetch
-//
+
+/*
+ sp_instr_cfetch class functions
+*/
+
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
int res;
+ Query_arena backup_current_arena;
DBUG_ENTER("sp_instr_cfetch::execute");
if (! c)
res= -1;
else
+ {
+ thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
res= c->fetch(thd, &m_varlist);
+ thd->restore_backup_item_arena(thd->spcont->callers_arena,
+ &backup_current_arena);
+ }
+
*nextp= m_ip+1;
DBUG_RETURN(res);
}
+
void
sp_instr_cfetch::print(String *str)
{
@@ -2178,9 +2310,11 @@ sp_instr_cfetch::print(String *str)
}
}
-//
-// sp_instr_error
-//
+
+/*
+ sp_instr_error class functions
+*/
+
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
@@ -2191,6 +2325,7 @@ sp_instr_error::execute(THD *thd, uint *nextp)
DBUG_RETURN(-1);
}
+
void
sp_instr_error::print(String *str)
{
@@ -2199,12 +2334,12 @@ sp_instr_error::print(String *str)
str->qs_append(m_errcode);
}
-/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------ */
-//
-// Security context swapping
-//
+/*
+ Security context swapping
+*/
#ifndef NO_EMBEDDED_ACCESS_CHECKS
void
@@ -2453,11 +2588,12 @@ sp_head::add_used_tables_to_table_list(THD *thd,
DBUG_RETURN(result);
}
+
/*
- * Simple function for adding an explicetly named (systems) table to
- * the global table list, e.g. "mysql", "proc".
- *
- */
+ Simple function for adding an explicetly named (systems) table to
+ the global table list, e.g. "mysql", "proc".
+*/
+
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
diff --git a/sql/sp_head.h b/sql/sp_head.h
index e15b68be158..8ae7834eb2a 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -714,7 +714,6 @@ public:
sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
: sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp)
{
- m_handler= ip+1;
m_cond.empty();
}
@@ -743,7 +742,6 @@ private:
int m_type; // Handler type
uint m_frame;
- uint m_handler; // Location of handler
List<struct sp_cond_type> m_cond;
}; // class sp_instr_hpush_jump : public sp_instr_jump
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index d0817e43790..748c09f56c7 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -32,7 +32,6 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
m_hfound(-1), m_ccount(0)
{
- callers_mem_root= NULL;
in_handler= FALSE;
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -47,17 +46,18 @@ sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
enum_field_types type)
{
extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
- Item *reuse);
+ Item *reuse, bool use_callers_arena);
Item *it;
Item *reuse_it;
Item *old_item_next;
- Item *old_free_list= thd->free_list;
+ /* sp_eval_func_item will use callers_arena */
+ Item *old_free_list= thd->spcont->callers_arena->free_list;
int res;
LINT_INIT(old_item_next);
if ((reuse_it= get_item(idx)))
old_item_next= reuse_it->next;
- it= sp_eval_func_item(thd, item_addr, type, reuse_it);
+ it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
if (! it)
res= -1;
else
@@ -67,7 +67,7 @@ sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
{
// A reused item slot, where the constructor put it in the free_list,
// so we have to restore the list.
- thd->free_list= old_free_list;
+ thd->spcont->callers_arena->free_list= old_free_list;
it->next= old_item_next;
}
set_item(idx, it);
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 856beb13f6d..dedbc7bdef1 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -48,8 +48,14 @@ class sp_rcontext : public Sql_alloc
public:
- MEM_ROOT *callers_mem_root; // Used to store result fields
bool in_handler;
+ /*
+ Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
+ SP parameters when they don't fit into prealloced items. This
+ is common situation with String items. It is used mainly in
+ sp_eval_func_item().
+ */
+ Query_arena *callers_arena;
sp_rcontext(uint fsize, uint hmax, uint cmax);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 5d2f5d55a7b..41b9257059d 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -67,7 +67,8 @@ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
static void init_check_host(void);
-static ACL_USER *find_acl_user(const char *host, const char *user);
+static ACL_USER *find_acl_user(const char *host, const char *user,
+ my_bool exact);
static bool update_user_table(THD *thd, const char *host, const char *user,
const char *new_password, uint new_password_len);
static void update_hostname(acl_host_and_ip *host, const char *hostname);
@@ -1288,7 +1289,7 @@ bool check_change_password(THD *thd, const char *host, const char *user,
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(system_charset_info, host, thd->host_or_ip)))
+ my_strcasecmp(system_charset_info, host, thd->priv_host)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
return(1);
@@ -1339,7 +1340,7 @@ bool change_password(THD *thd, const char *host, const char *user,
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
- if (!(acl_user= find_acl_user(host, user)))
+ if (!(acl_user= find_acl_user(host, user, TRUE)))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
@@ -1379,7 +1380,7 @@ bool change_password(THD *thd, const char *host, const char *user,
*/
static ACL_USER *
-find_acl_user(const char *host, const char *user)
+find_acl_user(const char *host, const char *user, my_bool exact)
{
DBUG_ENTER("find_acl_user");
DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user));
@@ -1395,7 +1396,9 @@ find_acl_user(const char *host, const char *user)
if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user))
{
- if (compare_hostname(&acl_user->host,host,host))
+ if (exact ? !my_strcasecmp(&my_charset_latin1, host,
+ acl_user->host.hostname) :
+ compare_hostname(&acl_user->host,host,host))
{
DBUG_RETURN(acl_user);
}
@@ -1821,7 +1824,7 @@ static int replace_db_table(TABLE *table, const char *db,
}
/* Check if there is such a user in user table in memory? */
- if (!find_acl_user(combo.host.str,combo.user.str))
+ if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
DBUG_RETURN(-1);
@@ -2368,7 +2371,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
The following should always succeed as new users are created before
this function is called!
*/
- if (!find_acl_user(combo.host.str,combo.user.str))
+ if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
MYF(0)); /* purecov: deadcode */
@@ -2490,7 +2493,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
The following should always succeed as new users are created before
this function is called!
*/
- if (!find_acl_user(combo.host.str,combo.user.str))
+ if (!find_acl_user(combo.host.str, combo.user.str, FALSE))
{
my_error(ER_PASSWORD_NO_MATCH,MYF(0));
DBUG_RETURN(-1);
@@ -2637,10 +2640,11 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
while ((column = column_iter++))
{
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
- Field *f=find_field_in_table(thd, table_list, column->column.ptr(),
- column->column.ptr(),
- column->column.length(), 0, 1, 1, 0,
- &unused_field_idx, FALSE);
+ TABLE_LIST *dummy;
+ Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
+ column->column.ptr(), NULL, NULL,
+ column->column.length(), 0, 1, 1, 0,
+ &unused_field_idx, FALSE, &dummy);
if (f == (Field*)0)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
@@ -3695,6 +3699,24 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
}
+/*
+ Determine the access priviliges for a field.
+
+ SYNOPSIS
+ get_column_grant()
+ thd thread handler
+ grant grants table descriptor
+ db_name name of database that the field belongs to
+ table_name name of table that the field belongs to
+ field_name name of field
+
+ DESCRIPTION
+ The procedure may also modify: grant->grant_table and grant->version.
+
+ RETURN
+ The access priviliges for the field db_name.table_name.field_name
+*/
+
ulong get_column_grant(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
const char *field_name)
@@ -4244,7 +4266,7 @@ void get_privilege_desc(char *to, uint max_length, ulong access)
void get_mqh(const char *user, const char *host, USER_CONN *uc)
{
ACL_USER *acl_user;
- if (initialized && (acl_user= find_acl_user(host,user)))
+ if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
uc->user_resources= acl_user->user_resource;
else
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
@@ -4589,11 +4611,12 @@ static int handle_grant_struct(uint struct_no, bool drop,
ACL_DB *acl_db;
GRANT_NAME *grant_name;
DBUG_ENTER("handle_grant_struct");
+ DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
+ struct_no, user_from->user.str, user_from->host.str));
+
LINT_INIT(acl_user);
LINT_INIT(acl_db);
LINT_INIT(grant_name);
- DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
- struct_no, user_from->user.str, user_from->host.str));
/* Get the number of elements in the in-memory structure. */
switch (struct_no) {
@@ -5289,10 +5312,12 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
combo->user.str= thd->user;
- if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str) &&
- !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str) &&
- !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str) &&
- !find_acl_user(combo->host.str=(char*)"%", combo->user.str))
+ if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str,
+ FALSE) &&
+ !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str,
+ FALSE) &&
+ !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) &&
+ !find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))
DBUG_RETURN(TRUE);
bzero((char*)tables, sizeof(TABLE_LIST));
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index dfed0e36b70..b8b96f14205 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -129,12 +129,11 @@ static void check_unused(void)
# Pointer to list of names of open tables.
*/
-OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
{
int result = 0;
OPEN_TABLE_LIST **start_list, *open_list;
TABLE_LIST table_list;
- char name[NAME_LEN*2];
DBUG_ENTER("list_open_tables");
VOID(pthread_mutex_lock(&LOCK_open));
@@ -151,12 +150,10 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
DBUG_ASSERT(share->table_name != 0);
if ((!share->table_name)) // To be removed
continue; // Shouldn't happen
- if (wild)
- {
- strxmov(name,share->table_cache_key,".",share->table_name,NullS);
- if (wild_compare(name,wild,0))
- continue;
- }
+ if (db && my_strcasecmp(system_charset_info, db, share->db))
+ continue;
+ if (wild && wild_compare(share->table_name,wild,0))
+ continue;
/* Check if user has SELECT privilege for any column in the table */
table_list.db= (char*) share->db;
@@ -404,8 +401,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
upper level) and will leave prelocked mode if needed.
*/
-void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
- TABLE *stopper)
+void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
{
bool found_old_table;
prelocked_mode_type prelocked_mode= thd->prelocked_mode;
@@ -502,7 +498,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
*/
bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
if (!thd->active_transaction())
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
if (!lock_in_use)
@@ -512,7 +508,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables));
found_old_table= 0;
- while (thd->open_tables != stopper)
+ while (thd->open_tables)
found_old_table|=close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0;
@@ -569,7 +565,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
else
{
// Free memory and reset for next loop
- table->file->ha_reset();
+ table->file->reset();
}
table->in_use=0;
if (unused_tables)
@@ -1047,35 +1043,61 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
+ bool check_if_used= thd->prelocked_mode &&
+ ((int) table_list->lock_type >=
+ (int) TL_WRITE_ALLOW_WRITE);
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->key_length == key_length &&
- !memcmp(table->s->table_cache_key, key, key_length) &&
- !my_strcasecmp(system_charset_info, table->alias, alias) &&
- table->query_id != thd->query_id && /* skip tables already used */
- !(thd->prelocked_mode && table->query_id))
+ !memcmp(table->s->table_cache_key, key, key_length))
{
- int distance= ((int) table->reginfo.lock_type -
- (int) table_list->lock_type);
- /*
- Find a table that either has the exact lock type requested,
- or has the best suitable lock. In case there is no locked
- table that has an equal or higher lock than requested,
- we us the closest matching lock to be able to produce an error
- message about wrong lock mode on the table. The best_table is changed
- if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.
-
- distance < 0 - No suitable lock found
- distance > 0 - we have lock mode higher then we require
- distance == 0 - we have lock mode exactly which we need
- */
- if (best_distance < 0 && distance > best_distance ||
- distance >= 0 && distance < best_distance)
+ if (check_if_used && table->query_id &&
+ table->query_id != thd->query_id)
{
- best_distance= distance;
- best_table= table;
- if (best_distance == 0) // Found perfect lock
- break;
+ /*
+ If we are in stored function or trigger we should ensure that
+ we won't change table that is already used by calling statement.
+ So if we are opening table for writing, we should check that it
+ is not already open by some calling stamement.
+ */
+ my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
+ table->s->table_name);
+ DBUG_RETURN(0);
+ }
+ if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
+ table->query_id != thd->query_id && /* skip tables already used */
+ !(thd->prelocked_mode && table->query_id))
+ {
+ int distance= ((int) table->reginfo.lock_type -
+ (int) table_list->lock_type);
+ /*
+ Find a table that either has the exact lock type requested,
+ or has the best suitable lock. In case there is no locked
+ table that has an equal or higher lock than requested,
+ we us the closest matching lock to be able to produce an error
+ message about wrong lock mode on the table. The best_table
+ is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.
+
+ distance < 0 - No suitable lock found
+ distance > 0 - we have lock mode higher then we require
+ distance == 0 - we have lock mode exactly which we need
+ */
+ if (best_distance < 0 && distance > best_distance ||
+ distance >= 0 && distance < best_distance)
+ {
+ best_distance= distance;
+ best_table= table;
+ if (best_distance == 0 && !check_if_used)
+ {
+ /*
+ If we have found perfect match and we don't need to check that
+ table is not used by one of calling statements (assuming that
+ we are inside of function or trigger) we can finish iterating
+ through open tables list.
+ */
+ break;
+ }
+ }
}
}
}
@@ -1669,7 +1691,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
{
/* Give right error message */
thd->clear_error();
- DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name));
+ DBUG_PRINT("error", ("Discovery of %s/%s failed", db, name));
my_printf_error(ER_UNKNOWN_ERROR,
"Failed to open '%-.64s', error while "
"unpacking from engine",
@@ -1804,6 +1826,9 @@ err:
thd - thread handler
start - list of tables in/out
counter - number of opened tables will be return using this parameter
+ flags - bitmap of flags to modify how the tables will be open:
+ MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
+ done a flush or namelock on it.
NOTE
Unless we are already in prelocked mode, this function will also precache
@@ -1821,7 +1846,7 @@ err:
-1 - error
*/
-int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
+int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
{
TABLE_LIST *tables;
bool refresh;
@@ -1900,7 +1925,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
(*counter)++;
if (!tables->table &&
- !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, 0)))
+ !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
{
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
@@ -1919,8 +1944,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
has added its base tables after itself, adjust the boundary pointer
accordingly.
*/
- if (query_tables_last_own &&
- query_tables_last_own == &(tables->next_global) &&
+ if (query_tables_last_own == &(tables->next_global) &&
tables->view->query_tables)
query_tables_last_own= tables->view->query_tables_last;
@@ -2143,7 +2167,8 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("simple_open_n_lock_tables");
uint counter;
- if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter))
+ if (open_tables(thd, &tables, &counter, 0) ||
+ lock_tables(thd, tables, counter))
DBUG_RETURN(-1); /* purecov: inspected */
DBUG_RETURN(0);
}
@@ -2170,7 +2195,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
uint counter;
DBUG_ENTER("open_and_lock_tables");
- if (open_tables(thd, &tables, &counter) ||
+ if (open_tables(thd, &tables, &counter, 0) ||
lock_tables(thd, tables, counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
@@ -2187,6 +2212,9 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
open_normal_and_derived_tables
thd - thread handler
tables - list of tables for open
+ flags - bitmap of flags to modify how the tables will be open:
+ MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
+ done a flush or namelock on it.
RETURN
FALSE - ok
@@ -2197,12 +2225,12 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
data from the tables.
*/
-bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
{
uint counter;
DBUG_ENTER("open_normal_and_derived_tables");
DBUG_ASSERT(!thd->fill_derived_tables());
- if (open_tables(thd, &tables, &counter) ||
+ if (open_tables(thd, &tables, &counter, flags) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */
DBUG_RETURN(0);
@@ -2466,190 +2494,243 @@ bool rm_temporary_table(enum db_type base, char *path)
/*****************************************************************************
-** find field in list or tables. if field is unqualifed and unique,
-** return unique field
+* The following find_field_in_XXX procedures implement the core of the
+* name resolution functionality. The entry point to resolve a column name in a
+* list of tables is 'find_field_in_tables'. It calls 'find_field_in_table_ref'
+* for each table reference. In turn, depending on the type of table reference,
+* 'find_field_in_table_ref' calls one of the 'find_field_in_XXX' procedures
+* below specific for the type of table reference.
******************************************************************************/
-/* Special Field pointers for find_field_in_tables returning */
+/* Special Field pointers as return values of find_field_in_XXX functions. */
Field *not_found_field= (Field*) 0x1;
Field *view_ref_found= (Field*) 0x2;
#define WRONG_GRANT (Field*) -1
+static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
+{
+ if (thd->set_query_id)
+ {
+ if (field->query_id != thd->query_id)
+ {
+ field->query_id= thd->query_id;
+ table->used_fields++;
+ table->used_keys.intersect(field->part_of_key);
+ }
+ else
+ thd->dupp_field= field;
+ }
+}
+
/*
- Find field in table or view
+ Find a field by name in a view that uses merge algorithm.
SYNOPSIS
- find_field_in_table()
+ find_field_in_view()
thd thread handler
- table_list table where to find
+ table_list view to search for 'name'
name name of field
item_name name of item if it will be created (VIEW)
length length of name
- ref [in/out] expression substituted in VIEW should be
- passed using this reference (return
- view_ref_found)
- (*ref != NULL) only if *ref contains
- the item that we need to replace.
- check_grants_table do check columns grants for table?
- check_grants_view do check columns grants for view?
- allow_rowid do allow finding of "_rowid" field?
- cached_field_index_ptr cached position in field list (used to
- speedup prepared tables field finding)
+ ref expression substituted in VIEW should be passed
+ using this reference (return view_ref_found)
+ check_grants do check columns grants for view?
register_tree_change TRUE if ref is not stack variable and we
- need register changes in item tree
+ need register changes in item tree
RETURN
0 field is not found
view_ref_found found value in VIEW (real result is in *ref)
- # pointer to field
+ # pointer to field - only for schema table fields
*/
-Field *
-find_field_in_table(THD *thd, TABLE_LIST *table_list,
- const char *name, const char *item_name,
- uint length, Item **ref,
- bool check_grants_table, bool check_grants_view,
- bool allow_rowid,
- uint *cached_field_index_ptr,
- bool register_tree_change)
+static Field *
+find_field_in_view(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ uint length, Item **ref, bool check_grants,
+ bool register_tree_change)
{
- Field *fld;
- DBUG_ENTER("find_field_in_table");
- DBUG_PRINT("enter", ("table: '%s' name: '%s' item name: '%s' ref 0x%lx",
- table_list->alias, name, item_name, (ulong) ref));
- if (table_list->field_translation)
+ DBUG_ENTER("find_field_in_view");
+ DBUG_PRINT("enter",
+ ("view: '%s', field name: '%s', item name: '%s', ref 0x%lx",
+ table_list->alias, name, item_name, (ulong) ref));
+ Field_iterator_view field_it;
+ field_it.set(table_list);
+ DBUG_ASSERT(table_list->schema_table_reformed ||
+ (ref != 0 && table_list->view != 0));
+ for (; !field_it.end_of_fields(); field_it.next())
{
- Field_iterator_view field_it;
- field_it.set(table_list);
- DBUG_ASSERT(table_list->schema_table_reformed ||
- (ref != 0 && table_list->view != 0));
- for (; !field_it.end_of_fields(); field_it.next())
+ if (!my_strcasecmp(system_charset_info, field_it.name(), name))
{
- if (!my_strcasecmp(system_charset_info, field_it.name(), name))
- {
- if (table_list->schema_table_reformed)
- {
- /*
- Translation table items are always Item_fields
- and fixed already('mysql_schema_table' function).
- So we can return ->field. It is used only for
- 'show & where' commands.
- */
- DBUG_RETURN(((Item_field*) (field_it.item()))->field);
- }
+ if (table_list->schema_table_reformed)
+ /*
+ Translation table items are always Item_fields and fixed already
+ ('mysql_schema_table' function). So we can return ->field. It is
+ used only for 'show & where' commands.
+ */
+ DBUG_RETURN(((Item_field*) (field_it.item()))->field);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants_view &&
- check_grant_column(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str,
- name, length))
- DBUG_RETURN(WRONG_GRANT);
+ if (check_grants &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ DBUG_RETURN(WRONG_GRANT);
#endif
- Item *item= field_it.create_item(thd);
- if (!item)
- {
- DBUG_RETURN(0);
- }
- /*
- *ref != NULL means that *ref contains the item that we need to
- replace. If the item was aliased by the user, set the alias to
- the replacing item.
- */
- if (*ref && !(*ref)->is_autogenerated_name)
- item->set_name((*ref)->name, (*ref)->name_length,
- system_charset_info);
- if (register_tree_change)
- thd->change_item_tree(ref, item);
- else
- *ref= item;
- DBUG_RETURN((Field*) view_ref_found);
- }
+ Item *item= field_it.create_item(thd);
+ if (!item)
+ DBUG_RETURN(0);
+ /*
+ *ref != NULL means that *ref contains the item that we need to
+ replace. If the item was aliased by the user, set the alias to
+ the replacing item.
+ */
+ if (*ref && !(*ref)->is_autogenerated_name)
+ item->set_name((*ref)->name, (*ref)->name_length,
+ system_charset_info);
+ if (register_tree_change)
+ thd->change_item_tree(ref, item);
+ else
+ *ref= item;
+ DBUG_RETURN((Field*) view_ref_found);
}
- DBUG_RETURN(0);
}
- fld= find_field_in_real_table(thd, table_list->table, name, length,
- check_grants_table, allow_rowid,
- cached_field_index_ptr);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* check for views with temporary table algorithm */
- if (check_grants_view && table_list->view &&
- fld && fld != WRONG_GRANT &&
- check_grant_column(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str,
- name, length))
- {
- DBUG_RETURN(WRONG_GRANT);
- }
-#endif
- DBUG_RETURN(fld);
+ DBUG_RETURN(0);
}
/*
- Find field in table, no side effects, only purpose is to check for field
- in table object and get reference to the field if found.
+ Find field by name in a NATURAL/USING join table reference.
SYNOPSIS
- find_field_in_table_sef()
+ find_field_in_natural_join()
+ thd [in] thread handler
+ table_ref [in] table reference to search
+ name [in] name of field
+ length [in] length of name
+ ref [in/out] if 'name' is resolved to a view field, ref is
+ set to point to the found view field
+ check_grants [in] do check columns grants?
+ register_tree_change [in] TRUE if ref is not stack variable and we
+ need register changes in item tree
+ actual_table [out] the original table reference where the field
+ belongs - differs from 'table_list' only for
+ NATURAL/USING joins
- table table where to find
- name Name of field searched for
+ DESCRIPTION
+ Search for a field among the result fields of a NATURAL/USING join.
+ Notice that this procedure is called only for non-qualified field
+ names. In the case of qualified fields, we search directly the base
+ tables of a natural join.
RETURN
- 0 field is not found
- # pointer to field
+ NULL if the field was not found
+ WRONG_GRANT if no access rights to the found field
+ # Pointer to the found Field
*/
-Field *find_field_in_table_sef(TABLE *table, const char *name)
+static Field *
+find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
+ uint length, Item **ref, bool check_grants,
+ bool register_tree_change,
+ TABLE_LIST **actual_table)
{
- Field **field_ptr;
- if (table->s->name_hash.records)
- field_ptr= (Field**)hash_search(&table->s->name_hash,(byte*) name,
- strlen(name));
- else
+ List_iterator_fast<Natural_join_column>
+ field_it(*(table_ref->join_columns));
+ Natural_join_column *nj_col;
+ Field *found_field;
+ DBUG_ENTER("find_field_in_natural_join");
+ DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx",
+ name, (ulong) ref));
+ DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns);
+ DBUG_ASSERT(*actual_table == NULL);
+
+ LINT_INIT(found_field);
+
+ for (;;)
{
- if (!(field_ptr= table->field))
- return (Field *)0;
- for (; *field_ptr; ++field_ptr)
- if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
- break;
+ if (!(nj_col= field_it++))
+ DBUG_RETURN(NULL);
+
+ if (!my_strcasecmp(system_charset_info, nj_col->name(), name))
+ break;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_grants && nj_col->check_grants(thd, name, length))
+ DBUG_RETURN(WRONG_GRANT);
+#endif
+
+ if (nj_col->view_field)
+ {
+ /*
+ The found field is a view field, we do as in find_field_in_view()
+ and return a pointer to pointer to the Item of that field.
+ */
+ Item *item= nj_col->create_item(thd);
+ if (!item)
+ DBUG_RETURN(NULL);
+ DBUG_ASSERT(nj_col->table_field == NULL);
+ if (nj_col->table_ref->schema_table_reformed)
+ {
+ /*
+ Translation table items are always Item_fields and fixed
+ already('mysql_schema_table' function). So we can return
+ ->field. It is used only for 'show & where' commands.
+ */
+ DBUG_RETURN(((Item_field*) (nj_col->view_field->item))->field);
+ }
+ if (register_tree_change)
+ thd->change_item_tree(ref, item);
+ else
+ *ref= item;
+ found_field= (Field*) view_ref_found;
}
- if (field_ptr)
- return *field_ptr;
else
- return (Field *)0;
+ {
+ /* This is a base table. */
+ DBUG_ASSERT(nj_col->view_field == NULL);
+ DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->table);
+ found_field= nj_col->table_field;
+ update_field_dependencies(thd, found_field, nj_col->table_ref->table);
+ }
+
+ *actual_table= nj_col->table_ref;
+
+ DBUG_RETURN(found_field);
}
/*
- Find field in table
+ Find field by name in a base table or a view with temp table algorithm.
SYNOPSIS
- find_field_in_real_table()
+ find_field_in_table()
thd thread handler
- table_list table where to find
+ table table where to search for the field
name name of field
length length of name
check_grants do check columns grants?
allow_rowid do allow finding of "_rowid" field?
- cached_field_index_ptr cached position in field list (used to
- speedup prepared tables field finding)
+ cached_field_index_ptr cached position in field list (used to speedup
+ lookup for fields in prepared tables)
RETURN
- 0 field is not found
- # pointer to field
+ 0 field is not found
+ # pointer to field
*/
-Field *find_field_in_real_table(THD *thd, TABLE *table,
- const char *name, uint length,
- bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr)
+Field *
+find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
+ bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr)
{
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
+ DBUG_ENTER("find_field_in_table");
+ DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name));
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
if (cached_field_index < table->s->fields &&
@@ -2662,7 +2743,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
else
{
if (!(field_ptr= table->field))
- return (Field *)0;
+ DBUG_RETURN((Field *)0);
for (; *field_ptr; ++field_ptr)
if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
break;
@@ -2678,32 +2759,141 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
if (!allow_rowid ||
my_strcasecmp(system_charset_info, name, "_rowid") ||
!(field=table->rowid_field))
- return (Field*) 0;
+ DBUG_RETURN((Field*) 0);
}
- if (thd->set_query_id)
- {
- table->file->ha_set_bit_in_rw_set(field->fieldnr,
- (bool)(thd->set_query_id-1));
- if (field->query_id != thd->query_id)
- {
- 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);
- }
- else
- thd->dupp_field=field;
- } else if (table->get_fields_in_item_tree)
- field->flags|= GET_FIXED_FIELDS_FLAG;
+ update_field_dependencies(thd, field, table);
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants && check_grant_column(thd, &table->grant,
table->s->db,
table->s->table_name, name, length))
- return WRONG_GRANT;
+ field= WRONG_GRANT;
#endif
- return field;
+ DBUG_RETURN(field);
+}
+
+
+/*
+ Find field in a table reference.
+
+ SYNOPSIS
+ find_field_in_table_ref()
+ thd [in] thread handler
+ table_list [in] table reference to search
+ name [in] name of field
+ item_name [in] name of item if it will be created (VIEW)
+ table_name [in] optional table name that qualifies the field
+ db_name [in] optional database name that qualifies the
+ length [in] field length of name
+ ref [in/out] if 'name' is resolved to a view field, ref
+ is set to point to the found view field
+ check_grants_table [in] do check columns grants for table?
+ check_grants_view [in] do check columns grants for view?
+ allow_rowid [in] do allow finding of "_rowid" field?
+ cached_field_index_ptr [in] cached position in field list (used to
+ speedup lookup for fields in prepared tables)
+ register_tree_change [in] TRUE if ref is not stack variable and we
+ need register changes in item tree
+ actual_table [out] the original table reference where the field
+ belongs - differs from 'table_list' only for
+ NATURAL_USING joins.
+
+ RETURN
+ 0 field is not found
+ view_ref_found found value in VIEW (real result is in *ref)
+ # pointer to field
+*/
+
+Field *
+find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ const char *table_name, const char *db_name,
+ uint length, Item **ref,
+ bool check_grants_table, bool check_grants_view,
+ bool allow_rowid, uint *cached_field_index_ptr,
+ bool register_tree_change, TABLE_LIST **actual_table)
+{
+ Field *fld;
+ DBUG_ENTER("find_field_in_table_ref");
+ DBUG_PRINT("enter",
+ ("table: '%s' field name: '%s' item name: '%s' ref 0x%lx",
+ table_list->alias, name, item_name, (ulong) ref));
+
+ /*
+ Check that the table and database that qualify the current field name
+ are the same as the table we are going to search for the field.
+ This is done differently for NATURAL/USING joins because there we can't
+ simply compare the qualifying table and database names with the ones of
+ 'table_list' because each field in such a join may originate from a
+ different table.
+ TODO: Ensure that table_name, db_name and tables->db always points to
+ something !
+ */
+ if (!table_list->is_natural_join &&
+ table_name && table_name[0] &&
+ (my_strcasecmp(table_alias_charset, table_list->alias, table_name) ||
+ (db_name && db_name[0] && table_list->db && table_list->db[0] &&
+ strcmp(db_name, table_list->db))))
+ DBUG_RETURN(0);
+
+ *actual_table= NULL;
+ if (table_list->field_translation)
+ {
+ if ((fld= find_field_in_view(thd, table_list, name, item_name, length,
+ ref, check_grants_view,
+ register_tree_change)))
+ *actual_table= table_list;
+ }
+ else if (table_list->is_natural_join)
+ {
+ if (table_name && table_name[0])
+ {
+ /*
+ Qualified field; Search for it in the tables used by the natural join.
+ */
+ List_iterator<TABLE_LIST> it(table_list->nested_join->join_list);
+ TABLE_LIST *table;
+ while ((table= it++))
+ {
+ if ((fld= find_field_in_table_ref(thd, table, name, item_name,
+ table_name, db_name, length, ref,
+ check_grants_table,
+ check_grants_view,
+ allow_rowid, cached_field_index_ptr,
+ register_tree_change, actual_table)))
+ DBUG_RETURN(fld);
+ }
+ DBUG_RETURN(0);
+ }
+ /*
+ Non-qualified field, search directly in the result columns of the
+ natural join.
+ */
+ fld= find_field_in_natural_join(thd, table_list, name, length, ref,
+ /* TIMOUR_TODO: check this with Sanja */
+ check_grants_table || check_grants_view,
+ register_tree_change, actual_table);
+ }
+ else
+ {
+ if ((fld= find_field_in_table(thd, table_list->table, name, length,
+ check_grants_table, allow_rowid,
+ cached_field_index_ptr)))
+ *actual_table= table_list;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* check for views with temporary table algorithm */
+ if (check_grants_view && table_list->view &&
+ fld && fld != WRONG_GRANT &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ fld= WRONG_GRANT;
+#endif
+ }
+
+ DBUG_RETURN(fld);
}
@@ -2712,21 +2902,23 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
SYNOPSIS
find_field_in_tables()
- thd Pointer to current thread structure
- item Field item that should be found
- tables Tables to be searched for item
- ref If 'item' is resolved to a view field, ref is set to
+ thd pointer to current thread structure
+ item field item that should be found
+ first_table list of tables to be searched for item
+ last_table end of the list of tables to search for item. If NULL
+ then search to the end of the list 'first_table'.
+ ref if 'item' is resolved to a view field, ref is set to
point to the found view field
- report_error Degree of error reporting:
+ report_error Degree of error reporting:
- IGNORE_ERRORS then do not report any error
- IGNORE_EXCEPT_NON_UNIQUE report only non-unique
- fields, suppress all other errors
+ fields, suppress all other errors
- REPORT_EXCEPT_NON_UNIQUE report all other errors
except when non-unique fields were found
- REPORT_ALL_ERRORS
check_privileges need to check privileges
- register_tree_change TRUE if ref is not stack variable and we
- need register changes in item tree
+ register_tree_change TRUE if ref is not a stack variable and we
+ to need register changes in item tree
RETURN VALUES
0 If error: the found field is not unique, or there are
@@ -2740,63 +2932,74 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
*/
Field *
-find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
+find_field_in_tables(THD *thd, Item_ident *item,
+ TABLE_LIST *first_table, TABLE_LIST *last_table,
Item **ref, find_item_error_report_type report_error,
bool check_privileges, bool register_tree_change)
{
Field *found=0;
- const char *db=item->db_name;
- const char *table_name=item->table_name;
- const char *name=item->field_name;
+ const char *db= item->db_name;
+ const char *table_name= item->table_name;
+ const char *name= item->field_name;
uint length=(uint) strlen(name);
char name_buff[NAME_LEN+1];
+ TABLE_LIST *cur_table= first_table;
+ TABLE_LIST *actual_table;
bool allow_rowid;
+ if (!table_name || !table_name[0])
+ {
+ table_name= 0; // For easier test
+ db= 0;
+ }
+
+ allow_rowid= table_name || (cur_table && !cur_table->next_local);
+
if (item->cached_table)
{
/*
- This shortcut is used by prepared statements. We assuming that
- TABLE_LIST *tables is not changed during query execution (which
+ This shortcut is used by prepared statements. We assume that
+ TABLE_LIST *first_table is not changed during query execution (which
is true for all queries except RENAME but luckily RENAME doesn't
use fields...) so we can rely on reusing pointer to its member.
With this optimization we also miss case when addition of one more
field makes some prepared query ambiguous and so erroneous, but we
accept this trade off.
*/
- if (item->cached_table->table && !item->cached_table->view)
- {
- found= find_field_in_real_table(thd, item->cached_table->table,
- name, length,
- test(item->cached_table->
- table->grant.want_privilege) &&
- check_privileges,
- 1, &(item->cached_field_index));
-
- }
+ TABLE_LIST *table_ref= item->cached_table;
+ /*
+ The condition (table_ref->view == NULL) ensures that we will call
+ find_field_in_table even in the case of information schema tables
+ when table_ref->field_translation != NULL.
+ */
+ if (table_ref->table && !table_ref->view)
+ found= find_field_in_table(thd, table_ref->table, name, length,
+ test(table_ref->table->
+ grant.want_privilege) &&
+ check_privileges,
+ 1, &(item->cached_field_index));
else
- {
- TABLE_LIST *table= item->cached_table;
- found= find_field_in_table(thd, table, name, item->name, length,
- ref,
- (table->table &&
- test(table->table->grant.
- want_privilege) &&
- check_privileges),
- (test(table->grant.want_privilege) &&
- check_privileges),
- 1, &(item->cached_field_index),
- register_tree_change);
- }
+ found= find_field_in_table_ref(thd, table_ref, name, item->name,
+ NULL, NULL, length, ref,
+ (table_ref->table &&
+ test(table_ref->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(table_ref->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index),
+ register_tree_change,
+ &actual_table);
if (found)
{
if (found == WRONG_GRANT)
return (Field*) 0;
{
SELECT_LEX *current_sel= thd->lex->current_select;
- SELECT_LEX *last_select= item->cached_table->select_lex;
+ SELECT_LEX *last_select= table_ref->select_lex;
/*
If the field was an outer referencee, mark all selects using this
- sub query as dependent of the outer query
+ sub query as dependent on the outer query
*/
if (current_sel != last_select)
mark_select_range_as_dependent(thd, last_select, current_sel,
@@ -2818,117 +3021,89 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
db= name_buff;
}
- if (table_name && table_name[0])
- { /* Qualified field */
- bool found_table= 0;
- for (; tables; tables= tables->next_local)
- {
- /* TODO; Ensure that db and tables->db always points to something ! */
- if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
- (!db || !db[0] || !tables->db || !tables->db[0] ||
- !strcmp(db,tables->db)))
- {
- found_table=1;
- Field *find= find_field_in_table(thd, tables, name, item->name,
- length, ref,
- (tables->table &&
- test(tables->table->grant.
- want_privilege) &&
- check_privileges),
- (test(tables->grant.want_privilege) &&
- check_privileges),
- 1, &(item->cached_field_index),
- register_tree_change);
- if (find)
- {
- item->cached_table= tables;
- if (!tables->cacheable_table)
- item->cached_table= 0;
- if (find == WRONG_GRANT)
- return (Field*) 0;
- if (db || !thd->where)
- return find;
- if (found)
- {
- if (report_error == REPORT_ALL_ERRORS ||
- report_error == IGNORE_EXCEPT_NON_UNIQUE)
- my_error(ER_NON_UNIQ_ERROR, MYF(0),
- item->full_name(),thd->where);
- return (Field*) 0;
- }
- found=find;
- }
- }
- }
- if (found)
- return found;
- if (!found_table && (report_error == REPORT_ALL_ERRORS ||
- report_error == REPORT_EXCEPT_NON_UNIQUE))
- {
- char buff[NAME_LEN*2+1];
- if (db && db[0])
- {
- strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
- table_name=buff;
- }
- my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
- }
- else
- if (report_error == REPORT_ALL_ERRORS ||
- report_error == REPORT_EXCEPT_NON_UNIQUE)
- my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
- else
- return (Field*) not_found_field;
- return (Field*) 0;
- }
- allow_rowid= tables && !tables->next_local; // Only one table
- for (; tables ; tables= tables->next_local)
- {
- Field *field;
- if (!tables->table && !tables->ancestor)
- {
- if (report_error == REPORT_ALL_ERRORS ||
- report_error == REPORT_EXCEPT_NON_UNIQUE)
- my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
- return (Field*) not_found_field;
- }
+ if (last_table)
+ last_table= last_table->next_name_resolution_table;
- field= find_field_in_table(thd, tables, name, item->name,
- length, ref,
- (tables->table &&
- test(tables->table->grant.
- want_privilege) &&
- check_privileges),
- (test(tables->grant.want_privilege) &&
- check_privileges),
- allow_rowid,
- &(item->cached_field_index),
- register_tree_change);
- if (field)
+ for (; cur_table != last_table ;
+ cur_table= cur_table->next_name_resolution_table)
+ {
+ Field *cur_field= find_field_in_table_ref(thd, cur_table, name, item->name,
+ table_name, db,
+ length, ref,
+ (cur_table->table &&
+ test(cur_table->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(cur_table->grant.
+ want_privilege)
+ && check_privileges),
+ allow_rowid,
+ &(item->cached_field_index),
+ register_tree_change,
+ &actual_table);
+ if (cur_field)
{
- if (field == WRONG_GRANT)
+ if (cur_field == WRONG_GRANT)
return (Field*) 0;
- item->cached_table= (!tables->cacheable_table || found) ? 0 : tables;
+
+ /*
+ Store the original table of the field, which may be different from
+ cur_table in the case of NATURAL/USING join.
+ */
+ item->cached_table= (!actual_table->cacheable_table || found) ?
+ 0 : actual_table;
+
+ DBUG_ASSERT(thd->where);
+ /*
+ If we found a fully qualified field we return it directly as it can't
+ have duplicates.
+ */
+ if (db)
+ return cur_field;
+
if (found)
{
- if (!thd->where) // Returns first found
- break;
if (report_error == REPORT_ALL_ERRORS ||
report_error == IGNORE_EXCEPT_NON_UNIQUE)
- my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ table_name ? item->full_name() : name, thd->where);
return (Field*) 0;
}
- found= field;
+ found= cur_field;
}
}
+
if (found)
return found;
- if (report_error == REPORT_ALL_ERRORS ||
- report_error == REPORT_EXCEPT_NON_UNIQUE)
- my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
+
+ /*
+ If the field was qualified and there were no tables to search, issue
+ an error that an unknown table was given. The situation is detected
+ as follows: if there were no tables we wouldn't go through the loop
+ and cur_table wouldn't be updated by the loop increment part, so it
+ will be equal to the first table.
+ */
+ if (table_name && (cur_table == first_table) &&
+ (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE))
+ {
+ char buff[NAME_LEN*2+1];
+ if (db && db[0])
+ {
+ strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
+ table_name=buff;
+ }
+ my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
+ }
else
- return (Field*) not_found_field;
- return (Field*) 0;
+ {
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
+ else
+ found= not_found_field;
+ }
+ return found;
}
@@ -3132,6 +3307,664 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
return (Item **) not_found_item;
}
+
+/*
+ Test if a string is a member of a list of strings.
+
+ SYNOPSIS
+ test_if_string_in_list()
+ find the string to look for
+ str_list a list of strings to be searched
+
+ DESCRIPTION
+ Sequentially search a list of strings for a string, and test whether
+ the list contains the same string.
+
+ RETURN
+ TRUE if find is in str_list
+ FALSE otherwise
+*/
+
+static bool
+test_if_string_in_list(const char *find, List<String> *str_list)
+{
+ List_iterator<String> str_list_it(*str_list);
+ String *curr_str;
+ size_t find_length= strlen(find);
+ while ((curr_str= str_list_it++))
+ {
+ if (find_length != curr_str->length())
+ continue;
+ if (!strncmp(find, curr_str->ptr(), find_length))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ Create a new name resolution context for an item so that it is
+ being resolved in a specific table reference.
+
+ SYNOPSIS
+ set_new_item_local_context()
+ thd pointer to current thread
+ item item for which new context is created and set
+ table_ref table ref where an item showld be resolved
+
+ DESCRIPTION
+ Create a new name resolution context for an item, so that the item
+ is resolved only the supplied 'table_ref'.
+
+ RETURN
+ FALSE if all OK
+ TRUE otherwise
+*/
+
+static bool
+set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref)
+{
+ Name_resolution_context *context;
+ if (!(context= new (thd->mem_root) Name_resolution_context))
+ return TRUE;
+ context->init();
+ context->first_name_resolution_table=
+ context->last_name_resolution_table= table_ref;
+ item->context= context;
+ return FALSE;
+}
+
+
+/*
+ Find and mark the common columns of two table references.
+
+ SYNOPSIS
+ mark_common_columns()
+ thd [in] current thread
+ table_ref_1 [in] the first (left) join operand
+ table_ref_2 [in] the second (right) join operand
+ using_fields [in] if the join is JOIN...USING - the join columns,
+ if NATURAL join, then NULL
+ found_using_fields [out] number of fields from the USING clause that were
+ found among the common fields
+
+ DESCRIPTION
+ The procedure finds the common columns of two relations (either
+ tables or intermediate join results), and adds an equi-join condition
+ to the ON clause of 'table_ref_2' for each pair of matching columns.
+ If some of table_ref_XXX represents a base table or view, then we
+ create new 'Natural_join_column' instances for each column
+ reference and store them in the 'join_columns' of the table
+ reference.
+
+ IMPLEMENTATION
+ The procedure assumes that store_natural_using_join_columns() was
+ called for the previous level of NATURAL/USING joins.
+
+ RETURN
+ TRUE error when some common column is non-unique, or out of memory
+ FALSE OK
+*/
+
+static bool
+mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
+ List<String> *using_fields, uint *found_using_fields)
+{
+ Field_iterator_table_ref it_1, it_2;
+ Natural_join_column *nj_col_1, *nj_col_2;
+ const char *field_name_1;
+ Query_arena *arena, backup;
+ bool add_columns= TRUE;
+ bool result= TRUE;
+
+ DBUG_ENTER("mark_common_columns");
+ DBUG_PRINT("info", ("operand_1: %s operand_2: %s",
+ table_ref_1->alias, table_ref_2->alias));
+
+ *found_using_fields= 0;
+ arena= thd->change_arena_if_needed(&backup);
+
+ /*
+ TABLE_LIST::join_columns could be allocated by the previous call to
+ store_natural_using_join_columns() for the lower level of nested tables.
+ */
+ if (!table_ref_1->join_columns)
+ {
+ if (!(table_ref_1->join_columns= new List<Natural_join_column>))
+ goto err;
+ table_ref_1->is_join_columns_complete= FALSE;
+ }
+ if (!table_ref_2->join_columns)
+ {
+ if (!(table_ref_2->join_columns= new List<Natural_join_column>))
+ goto err;
+ table_ref_2->is_join_columns_complete= FALSE;
+ }
+
+ for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
+ {
+ bool is_created_1;
+ bool found= FALSE;
+ if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created_1)))
+ goto err;
+ field_name_1= nj_col_1->name();
+
+ /* If nj_col_1 was just created add it to the list of join columns. */
+ if (is_created_1)
+ table_ref_1->join_columns->push_back(nj_col_1);
+
+ /*
+ Find a field with the same name in table_ref_2.
+
+ Note that for the second loop, it_2.set() will iterate over
+ table_ref_2->join_columns and not generate any new elements or
+ lists.
+ */
+ nj_col_2= NULL;
+ for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
+ {
+ bool is_created_2;
+ Natural_join_column *cur_nj_col_2;
+ const char *cur_field_name_2;
+ if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, &is_created_2)))
+ goto err;
+ cur_field_name_2= cur_nj_col_2->name();
+
+ /* If nj_col_1 was just created add it to the list of join columns. */
+ if (add_columns && is_created_2)
+ table_ref_2->join_columns->push_back(cur_nj_col_2);
+
+ /* Compare the two columns and check for duplicate common fields. */
+ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2))
+ {
+ if (found)
+ {
+ my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where);
+ goto err;
+ }
+ nj_col_2= cur_nj_col_2;
+ found= TRUE;
+ }
+ }
+ /* Force it_2.set() to use table_ref_2->join_columns. */
+ table_ref_2->is_join_columns_complete= TRUE;
+ add_columns= FALSE;
+ if (!found)
+ continue; // No matching field
+
+ /*
+ field_1 and field_2 have the same names. Check if they are in the USING
+ clause (if present), mark them as common fields, and add a new
+ equi-join condition to the ON clause.
+ */
+ if (nj_col_2 &&
+ (!using_fields ||
+ test_if_string_in_list(field_name_1, using_fields)))
+ {
+ Item *item_1= nj_col_1->create_item(thd);
+ Item *item_2= nj_col_2->create_item(thd);
+ Field *field_1= nj_col_1->field();
+ Field *field_2= nj_col_2->field();
+ Item_ident *item_ident_1, *item_ident_2;
+ Item_func_eq *eq_cond;
+
+ if (!item_1 || !item_2)
+ goto err; // out of memory
+
+ /*
+ The following assert checks that the two created items are of
+ type Item_ident.
+ */
+ DBUG_ASSERT(!thd->lex->current_select->no_wrap_view_item);
+ /*
+ In the case of no_wrap_view_item == 0, the created items must be
+ of sub-classes of Item_ident.
+ */
+ DBUG_ASSERT(item_1->type() == Item::FIELD_ITEM ||
+ item_1->type() == Item::REF_ITEM);
+ DBUG_ASSERT(item_2->type() == Item::FIELD_ITEM ||
+ item_2->type() == Item::REF_ITEM);
+
+ /*
+ We need to cast item_1,2 to Item_ident, because we need to hook name
+ resolution contexts specific to each item.
+ */
+ item_ident_1= (Item_ident*) item_1;
+ item_ident_2= (Item_ident*) item_2;
+ /*
+ Create and hook special name resolution contexts to each item in the
+ new join condition . We need this to both speed-up subsequent name
+ resolution of these items, and to enable proper name resolution of
+ the items during the execute phase of PS.
+ */
+ if (set_new_item_local_context(thd, item_ident_1, nj_col_1->table_ref) ||
+ set_new_item_local_context(thd, item_ident_2, nj_col_2->table_ref))
+ goto err;
+
+ if (!(eq_cond= new Item_func_eq(item_ident_1, item_ident_2)))
+ goto err; /* Out of memory. */
+
+ /*
+ Add the new equi-join condition to the ON clause. Notice that
+ fix_fields() is applied to all ON conditions in setup_conds()
+ so we don't do it here.
+ */
+ add_join_on((table_ref_1->outer_join & JOIN_TYPE_RIGHT ?
+ table_ref_1 : table_ref_2),
+ eq_cond);
+
+ nj_col_1->is_common= nj_col_2->is_common= TRUE;
+
+ if (field_1)
+ {
+ /* Mark field_1 used for table cache. */
+ field_1->query_id= thd->query_id;
+ nj_col_1->table_ref->table->used_keys.intersect(field_1->part_of_key);
+ }
+ if (field_2)
+ {
+ /* Mark field_2 used for table cache. */
+ field_2->query_id= thd->query_id;
+ nj_col_2->table_ref->table->used_keys.intersect(field_2->part_of_key);
+ }
+
+ if (using_fields != NULL)
+ ++(*found_using_fields);
+ }
+ }
+ table_ref_1->is_join_columns_complete= TRUE;
+
+ /*
+ Everything is OK.
+ Notice that at this point there may be some column names in the USING
+ clause that are not among the common columns. This is an SQL error and
+ we check for this error in store_natural_using_join_columns() when
+ (found_using_fields < length(join_using_fields)).
+ */
+ result= FALSE;
+
+err:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ DBUG_RETURN(result);
+}
+
+
+
+/*
+ Materialize and store the row type of NATURAL/USING join.
+
+ SYNOPSIS
+ store_natural_using_join_columns()
+ thd current thread
+ natural_using_join the table reference of the NATURAL/USING join
+ table_ref_1 the first (left) operand (of a NATURAL/USING join).
+ table_ref_2 the second (right) operand (of a NATURAL/USING join).
+ using_fields if the join is JOIN...USING - the join columns,
+ if NATURAL join, then NULL
+ found_using_fields number of fields from the USING clause that were
+ found among the common fields
+
+ DESCRIPTION
+ Iterate over the columns of both join operands and sort and store
+ all columns into the 'join_columns' list of natural_using_join
+ where the list is formed by three parts:
+ part1: The coalesced columns of table_ref_1 and table_ref_2,
+ sorted according to the column order of the first table.
+ part2: The other columns of the first table, in the order in
+ which they were defined in CREATE TABLE.
+ part3: The other columns of the second table, in the order in
+ which they were defined in CREATE TABLE.
+ Time complexity - O(N1+N2), where Ni = length(table_ref_i).
+
+ IMPLEMENTATION
+ The procedure assumes that mark_common_columns() has been called
+ for the join that is being processed.
+
+ RETURN
+ TRUE error: Some common column is ambiguous
+ FALSE OK
+*/
+
+static bool
+store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
+ TABLE_LIST *table_ref_1,
+ TABLE_LIST *table_ref_2,
+ List<String> *using_fields,
+ uint found_using_fields)
+{
+ Field_iterator_table_ref it_1, it_2;
+ Natural_join_column *nj_col_1, *nj_col_2;
+ bool is_created;
+ Query_arena *arena, backup;
+ bool result= TRUE;
+ List<Natural_join_column> *non_join_columns;
+ DBUG_ENTER("store_natural_using_join_columns");
+
+ DBUG_ASSERT(!natural_using_join->join_columns);
+
+ arena= thd->change_arena_if_needed(&backup);
+
+ if (!(non_join_columns= new List<Natural_join_column>) ||
+ !(natural_using_join->join_columns= new List<Natural_join_column>))
+ goto err;
+
+ /* Append the columns of the first join operand. */
+ for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
+ {
+ if (!(nj_col_1= it_1.get_or_create_column_ref(thd, &is_created)))
+ goto err;
+ /*
+ The following assert checks that mark_common_columns() was run and
+ we created the list table_ref_1->join_columns.
+ */
+ DBUG_ASSERT(!is_created);
+ if (nj_col_1->is_common)
+ {
+ natural_using_join->join_columns->push_back(nj_col_1);
+ /* Reset the common columns for the next call to mark_common_columns. */
+ nj_col_1->is_common= FALSE;
+ }
+ else
+ non_join_columns->push_back(nj_col_1);
+ }
+
+ /*
+ Check that all columns in the USING clause are among the common
+ columns. If this is not the case, report the first one that was
+ not found in an error.
+ */
+ if (using_fields && found_using_fields < using_fields->elements)
+ {
+ String *using_field_name;
+ List_iterator_fast<String> using_fields_it(*using_fields);
+ while ((using_field_name= using_fields_it++))
+ {
+ const char *using_field_name_ptr= using_field_name->c_ptr();
+ List_iterator_fast<Natural_join_column>
+ it(*(natural_using_join->join_columns));
+ Natural_join_column *common_field;
+
+ for (;;)
+ {
+ /* If reached the end of fields, and none was found, report error. */
+ if (!(common_field= it++))
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr,
+ current_thd->where);
+ goto err;
+ }
+ if (!my_strcasecmp(system_charset_info,
+ common_field->name(), using_field_name_ptr))
+ break; // Found match
+ }
+ }
+ }
+
+ /* Append the non-equi-join columns of the second join operand. */
+ for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
+ {
+ if (!(nj_col_2= it_2.get_or_create_column_ref(thd, &is_created)))
+ goto err;
+ /*
+ The following assert checks that mark_common_columns() was run and
+ we created the list table_ref_2->join_columns.
+ */
+ DBUG_ASSERT(!is_created);
+ if (!nj_col_2->is_common)
+ non_join_columns->push_back(nj_col_2);
+ else
+ {
+ /* Reset the common columns for the next call to mark_common_columns. */
+ nj_col_2->is_common= FALSE;
+ }
+ }
+
+ if (non_join_columns->elements > 0)
+ natural_using_join->join_columns->concat(non_join_columns);
+ natural_using_join->is_join_columns_complete= TRUE;
+
+ result= FALSE;
+
+err:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Precompute and store the row types of the top-most NATURAL/USING joins.
+
+ SYNOPSIS
+ store_top_level_join_columns()
+ thd current thread
+ table_ref nested join or table in a FROM clause
+ left_neighbor neighbor table reference to the left of table_ref at the
+ same level in the join tree
+ right_neighbor neighbor table reference to the right of table_ref at the
+ same level in the join tree
+
+ DESCRIPTION
+ The procedure performs a post-order traversal of a nested join tree
+ and materializes the row types of NATURAL/USING joins in a
+ bottom-up manner until it reaches the TABLE_LIST elements that
+ represent the top-most NATURAL/USING joins. The procedure should be
+ applied to each element of SELECT_LEX::top_join_list (i.e. to each
+ top-level element of the FROM clause).
+
+ IMPLEMENTATION
+ Notice that the table references in the list nested_join->join_list
+ are in reverse order, thus when we iterate over it, we are moving
+ from the right to the left in the FROM clause.
+
+ RETURN
+ TRUE Error
+ FALSE OK
+*/
+
+static bool
+store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref,
+ TABLE_LIST *left_neighbor,
+ TABLE_LIST *right_neighbor)
+{
+ Query_arena *arena, backup;
+ bool result= TRUE;
+
+ DBUG_ENTER("store_top_level_join_columns");
+
+ arena= thd->change_arena_if_needed(&backup);
+
+ /* Call the procedure recursively for each nested table reference. */
+ if (table_ref->nested_join)
+ {
+ List_iterator_fast<TABLE_LIST> nested_it(table_ref->nested_join->join_list);
+ TABLE_LIST *cur_left_neighbor= nested_it++;
+ TABLE_LIST *cur_right_neighbor= NULL;
+
+ while (cur_left_neighbor)
+ {
+ TABLE_LIST *cur_table_ref= cur_left_neighbor;
+ cur_left_neighbor= nested_it++;
+ /*
+ The order of RIGHT JOIN operands is reversed in 'join list' to
+ transform it into a LEFT JOIN. However, in this procedure we need
+ the join operands in their lexical order, so below we reverse the
+ join operands. Notice that this happens only in the first loop, and
+ not in the second one, as in the second loop cur_left_neighbor == NULL.
+ This is the correct behavior, because the second loop
+ sets cur_table_ref reference correctly after the join operands are
+ swapped in the first loop.
+ */
+ if (cur_left_neighbor &&
+ cur_table_ref->outer_join & JOIN_TYPE_RIGHT)
+ {
+ /* This can happen only for JOIN ... ON. */
+ DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2);
+ swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref);
+ }
+
+ if (cur_table_ref->nested_join &&
+ store_top_level_join_columns(thd, cur_table_ref,
+ cur_left_neighbor, cur_right_neighbor))
+ goto err;
+ cur_right_neighbor= cur_table_ref;
+ }
+ }
+
+ /*
+ If this is a NATURAL/USING join, materialize its result columns and
+ convert to a JOIN ... ON.
+ */
+ if (table_ref->is_natural_join)
+ {
+ DBUG_ASSERT(table_ref->nested_join &&
+ table_ref->nested_join->join_list.elements == 2);
+ List_iterator_fast<TABLE_LIST> operand_it(table_ref->nested_join->join_list);
+ /*
+ Notice that the order of join operands depends on whether table_ref
+ represents a LEFT or a RIGHT join. In a RIGHT join, the operands are
+ in inverted order.
+ */
+ TABLE_LIST *table_ref_2= operand_it++; /* Second NATURAL join operand.*/
+ TABLE_LIST *table_ref_1= operand_it++; /* First NATURAL join operand. */
+ List<String> *using_fields= table_ref->join_using_fields;
+ uint found_using_fields;
+
+ /*
+ The two join operands were interchanged in the parser, change the order
+ back for 'mark_common_columns'.
+ */
+ if (table_ref_2->outer_join & JOIN_TYPE_RIGHT)
+ swap_variables(TABLE_LIST*, table_ref_1, table_ref_2);
+ if (mark_common_columns(thd, table_ref_1, table_ref_2,
+ using_fields, &found_using_fields))
+ goto err;
+
+ /*
+ Swap the join operands back, so that we pick the columns of the second
+ one as the coalesced columns. In this way the coalesced columns are the
+ same as of an equivalent LEFT JOIN.
+ */
+ if (table_ref_1->outer_join & JOIN_TYPE_RIGHT)
+ swap_variables(TABLE_LIST*, table_ref_1, table_ref_2);
+ if (store_natural_using_join_columns(thd, table_ref, table_ref_1,
+ table_ref_2, using_fields,
+ found_using_fields))
+ goto err;
+
+ /*
+ Change NATURAL JOIN to JOIN ... ON. We do this for both operands
+ because either one of them or the other is the one with the
+ natural join flag because RIGHT joins are transformed into LEFT,
+ and the two tables may be reordered.
+ */
+ table_ref_1->natural_join= table_ref_2->natural_join= NULL;
+
+ /* Add a TRUE condition to outer joins that have no common columns. */
+ if (table_ref_2->outer_join &&
+ !table_ref_1->on_expr && !table_ref_2->on_expr)
+ table_ref_2->on_expr= new Item_int((longlong) 1,1); /* Always true. */
+
+ /* Change this table reference to become a leaf for name resolution. */
+ if (left_neighbor)
+ {
+ TABLE_LIST *last_leaf_on_the_left;
+ last_leaf_on_the_left= left_neighbor->last_leaf_for_name_resolution();
+ last_leaf_on_the_left->next_name_resolution_table= table_ref;
+ }
+ if (right_neighbor)
+ {
+ TABLE_LIST *first_leaf_on_the_right;
+ first_leaf_on_the_right= right_neighbor->first_leaf_for_name_resolution();
+ table_ref->next_name_resolution_table= first_leaf_on_the_right;
+ }
+ else
+ table_ref->next_name_resolution_table= NULL;
+ }
+ result= FALSE; /* All is OK. */
+
+err:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Compute and store the row types of the top-most NATURAL/USING joins
+ in a FROM clause.
+
+ SYNOPSIS
+ setup_natural_join_row_types()
+ thd current thread
+ from_clause list of top-level table references in a FROM clause
+
+ DESCRIPTION
+ Apply the procedure 'store_top_level_join_columns' to each of the
+ top-level table referencs of the FROM clause. Adjust the list of tables
+ for name resolution - context->first_name_resolution_table to the
+ top-most, lef-most NATURAL/USING join.
+
+ IMPLEMENTATION
+ Notice that the table references in 'from_clause' are in reverse
+ order, thus when we iterate over it, we are moving from the right
+ to the left in the FROM clause.
+
+ RETURN
+ TRUE Error
+ FALSE OK
+*/
+static bool setup_natural_join_row_types(THD *thd,
+ List<TABLE_LIST> *from_clause,
+ Name_resolution_context *context)
+{
+ thd->where= "from clause";
+ if (from_clause->elements == 0)
+ return FALSE; /* We come here in the case of UNIONs. */
+
+ /* For stored procedures do not redo work if already done. */
+ if (!context->select_lex->first_execution)
+ return FALSE;
+
+ List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause);
+ TABLE_LIST *table_ref; /* Current table reference. */
+ /* Table reference to the left of the current. */
+ TABLE_LIST *left_neighbor;
+ /* Table reference to the right of the current. */
+ TABLE_LIST *right_neighbor= NULL;
+
+ /* Note that tables in the list are in reversed order */
+ for (left_neighbor= table_ref_it++; left_neighbor ; )
+ {
+ table_ref= left_neighbor;
+ left_neighbor= table_ref_it++;
+ if (store_top_level_join_columns(thd, table_ref,
+ left_neighbor, right_neighbor))
+ return TRUE;
+ if (left_neighbor)
+ {
+ TABLE_LIST *first_leaf_on_the_right;
+ first_leaf_on_the_right= table_ref->first_leaf_for_name_resolution();
+ left_neighbor->next_name_resolution_table= first_leaf_on_the_right;
+ }
+ right_neighbor= table_ref;
+ }
+
+ /*
+ Store the top-most, left-most NATURAL/USING join, so that we start
+ the search from that one instead of context->table_list. At this point
+ right_neighbor points to the left-most top-level table reference in the
+ FROM clause.
+ */
+ DBUG_ASSERT(right_neighbor);
+ context->first_name_resolution_table=
+ right_neighbor->first_leaf_for_name_resolution();
+
+ return FALSE;
+}
+
+
/****************************************************************************
** Expand all '*' in given fields
****************************************************************************/
@@ -3212,10 +4045,11 @@ 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, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func)
{
reg2 Item *item;
+ bool save_set_query_id= thd->set_query_id;
List_iterator<Item> it(fields);
DBUG_ENTER("setup_fields");
@@ -3243,6 +4077,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
+ thd->set_query_id= save_set_query_id;
DBUG_RETURN(TRUE); /* purecov: inspected */
}
if (ref)
@@ -3250,8 +4085,9 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
- thd->used_tables|=item->used_tables();
+ thd->used_tables|= item->used_tables();
}
+ thd->set_query_id= save_set_query_id;
DBUG_RETURN(test(thd->net.report_error));
}
@@ -3272,9 +4108,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE)
- {
list= make_leaves_list(list, table->ancestor);
- }
else
{
*list= table;
@@ -3291,33 +4125,36 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
setup_tables()
thd Thread handler
context name resolution contest to setup table list there
- tables Table list
+ 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
+ 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
NOTE
Check also that the 'used keys' and 'ignored keys' exists and set up the
- table structure accordingly
- Create leaf tables list
+ table structure accordingly.
+ Create a list of leaf tables. For queries with NATURAL/USING JOINs,
+ compute the row types of the top most natural/using join table references
+ and link these into a list of table references for name resolution.
This has to be called for all tables that are used by items, as otherwise
table->map is not set and all Item_field will be regarded as const items.
RETURN
- FALSE ok; In this case *map will includes the choosed index
+ FALSE ok; In this case *map will includes the chosen index
TRUE error
*/
bool setup_tables(THD *thd, Name_resolution_context *context,
- TABLE_LIST *tables, Item **conds,
- TABLE_LIST **leaves, bool select_insert)
+ List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
+ Item **conds, TABLE_LIST **leaves, bool select_insert)
{
uint tablenr= 0;
DBUG_ENTER("setup_tables");
- context->table_list= tables;
+ context->table_list= context->first_name_resolution_table= tables;
/*
this is used for INSERT ... SELECT.
@@ -3389,6 +4226,11 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
DBUG_RETURN(1);
}
}
+
+ /* Precompute and store the row types of NATURAL/USING joins. */
+ if (setup_natural_join_row_types(thd, from_clause, context))
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
}
@@ -3447,8 +4289,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
for all columns
1 If any privilege is ok
RETURN
- 0 ok
- 'it' is updated to point at last inserted
+ 0 ok 'it' is updated to point at last inserted
1 error. Error message is generated but not sent to client
*/
@@ -3457,12 +4298,11 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
const char *table_name, List_iterator<Item> *it,
bool any_privileges)
{
- /* allocate variables on stack to avoid pool alloaction */
- Field_iterator_table table_iter;
- Field_iterator_view view_iter;
- uint found;
+ Field_iterator_table_ref field_iterator;
+ bool found;
char name_buff[NAME_LEN+1];
DBUG_ENTER("insert_fields");
+ DBUG_PRINT("arena", ("current arena: 0x%lx", (ulong)thd->current_arena));
if (db_name && lower_case_table_names)
{
@@ -3476,200 +4316,192 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
db_name= name_buff;
}
- found= 0;
- for (TABLE_LIST *tables= context->table_list;
+ found= FALSE;
+
+ /*
+ If table names are qualified, then loop over all tables used in the query,
+ else treat natural joins as leaves and do not iterate over their underlying
+ tables.
+ */
+ for (TABLE_LIST *tables= (table_name ? context->table_list :
+ context->first_name_resolution_table);
tables;
- tables= tables->next_local)
+ tables= (table_name ? tables->next_local :
+ tables->next_name_resolution_table)
+ )
{
- Field_iterator *iterator;
- TABLE_LIST *natural_join_table;
Field *field;
- TABLE_LIST *embedded;
- TABLE_LIST *last;
- TABLE_LIST *embedding;
TABLE *table= tables->table;
- if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
- tables->alias) &&
- (!db_name || !strcmp(tables->db,db_name))))
- {
- bool view;
+ DBUG_ASSERT(tables->is_leaf_for_name_resolution());
+
+ if (table_name && my_strcasecmp(table_alias_charset, table_name,
+ tables->alias) ||
+ (db_name && strcmp(tables->db,db_name)))
+ continue;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* Ensure that we have access right to all columns */
- if (!((table && (table->grant.privilege & SELECT_ACL) ||
- tables->view && (tables->grant.privilege & SELECT_ACL))) &&
- !any_privileges)
- {
- if (tables->view)
- {
- view_iter.set(tables);
- if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
- tables->view_db.str,
- tables->view_name.str,
- &view_iter))
- goto err;
- }
- else if (!tables->schema_table)
- {
- DBUG_ASSERT(table != 0);
- table_iter.set(tables);
- if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
- table->s->db,
- table->s->table_name,
- &table_iter))
- goto err;
- }
- }
+ /* Ensure that we have access rights to all fields to be inserted. */
+ if (!((table && (table->grant.privilege & SELECT_ACL) ||
+ tables->view && (tables->grant.privilege & SELECT_ACL))) &&
+ !any_privileges)
+ {
+ field_iterator.set(tables);
+ if (check_grant_all_columns(thd, SELECT_ACL, field_iterator.grant(),
+ field_iterator.db_name(),
+ field_iterator.table_name(),
+ &field_iterator))
+ DBUG_RETURN(TRUE);
+ }
#endif
- natural_join_table= 0;
- last= embedded= tables;
- while ((embedding= embedded->embedding) &&
- embedding->join_list->elements != 1)
- {
- TABLE_LIST *next;
- List_iterator_fast<TABLE_LIST> it(embedding->nested_join->join_list);
- last= it++;
- while ((next= it++))
- last= next;
- if (last != tables)
- break;
- embedded= embedding;
- }
- if (tables == last &&
- !embedded->outer_join &&
- embedded->natural_join &&
- !embedded->natural_join->outer_join)
- {
- embedding= embedded->natural_join;
- while (embedding->nested_join)
- embedding= embedding->nested_join->join_list.head();
- natural_join_table= embedding;
- }
- if (tables->field_translation)
+ /*
+ 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.
+ */
+ if (table)
+ thd->used_tables|= table->map;
+
+ /*
+ Initialize a generic field iterator for the current table reference.
+ Notice that it is guaranteed that this iterator will iterate over the
+ fields of a single table reference, because 'tables' is a leaf (for
+ name resolution purposes).
+ */
+ field_iterator.set(tables);
+
+ for (; !field_iterator.end_of_fields(); field_iterator.next())
+ {
+ Item *item;
+
+ if (!(item= field_iterator.create_item(thd)))
+ DBUG_RETURN(TRUE);
+
+ if (!found)
{
- iterator= &view_iter;
- view= 1;
+ found= TRUE;
+ it->replace(item); /* Replace '*' with the first found item. */
}
else
- {
- iterator= &table_iter;
- view= 0;
- }
- iterator->set(tables);
-
- /* for view used tables will be collected in following loop */
- if (table)
- thd->used_tables|= table->map;
+ it->after(item); /* Add 'item' to the SELECT list. */
- for (; !iterator->end_of_fields(); iterator->next())
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Set privilege information for the fields of newly created views.
+ We have that (any_priviliges == TRUE) if and only if we are creating
+ a view. In the time of view creation we can't use the MERGE algorithm,
+ therefore if 'tables' is itself a view, it is represented by a
+ temporary table. Thus in this case we can be sure that 'item' is an
+ Item_field.
+ */
+ if (any_privileges)
{
- Item *not_used_item;
- uint not_used_field_index= NO_CACHED_FIELD_INDEX;
- const char *field_name= iterator->name();
- /* Skip duplicate field names if NATURAL JOIN is used */
- if (!natural_join_table ||
- !find_field_in_table(thd, natural_join_table, field_name,
- field_name,
- strlen(field_name), &not_used_item, 0, 0, 0,
- &not_used_field_index, TRUE))
+ DBUG_ASSERT(tables->field_translation == NULL && table ||
+ tables->is_natural_join);
+ DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
+ Item_field *fld= (Item_field*) item;
+ const char *field_table_name= field_iterator.table_name();
+
+ if (!tables->schema_table &&
+ !(fld->have_privileges=
+ (get_column_grant(thd, field_iterator.grant(),
+ field_iterator.db_name(),
+ field_table_name, fld->field_name) &
+ VIEW_ANY_ACL)))
{
- Item *item= iterator->create_item(thd);
- if (!item)
- goto err;
- thd->used_tables|= item->used_tables();
- if (!found++)
- (void) it->replace(item); // Replace '*'
- else
- it->after(item);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (any_privileges)
- {
- /*
- In time of view creation MEGRGE algorithm for underlying
- VIEWs can't be used => it should be Item_field
- */
- DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
- Item_field *fld= (Item_field*)item;
- char *db, *tab;
- if (tables->view)
- {
- db= tables->view_db.str;
- tab= tables->view_name.str;
- }
- else
- {
- db= tables->db;
- tab= tables->table_name;
- }
- if (!tables->schema_table &&
- !(fld->have_privileges= (get_column_grant(thd,
- &table->grant,
- db,
- tab,
- fld->field_name) &
- VIEW_ANY_ACL)))
- {
- my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
- "ANY",
- thd->priv_user,
- thd->host_or_ip,
- fld->field_name,
- tab);
- goto err;
- }
- }
-#endif
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY",
+ thd->priv_user, thd->host_or_ip,
+ fld->field_name, field_table_name);
+ DBUG_RETURN(TRUE);
}
- if ((field= iterator->field()))
+ }
+#endif
+
+ 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;
+
+ if (table)
+ table->used_keys.intersect(field->part_of_key);
+
+ if (tables->is_natural_join)
{
+ bool is_created;
+ TABLE *field_table;
/*
- Mark if field used before in this select.
- Used by 'insert' to verify if a field name is used twice
+ In this case we are sure that the column ref will not be created
+ because it was already created and stored with the natural join.
*/
- if (field->query_id == thd->query_id)
- thd->dupp_field=field;
- field->query_id=thd->query_id;
- table->used_keys.intersect(field->part_of_key);
- }
- else
- {
- Item *item= ((Field_iterator_view *) iterator)->item();
- item->walk(&Item::reset_query_id_processor,
- (byte *)(&thd->query_id));
+ Natural_join_column *nj_col;
+ if (!(nj_col= field_iterator.get_or_create_column_ref(thd,
+ &is_created)))
+ DBUG_RETURN(TRUE);
+ DBUG_ASSERT(nj_col->table_field && !is_created);
+ field_table= nj_col->table_ref->table;
+ if (field_table)
+ {
+ thd->used_tables|= field_table->map;
+ field_table->used_keys.intersect(field->part_of_key);
+ field_table->used_fields++;
+ }
}
}
- /*
- All fields are used in case if usual tables (in case of view used
- fields marked in setup_tables during fix_fields of view columns
- */
- if (table)
+ else
{
- table->used_fields= table->s->fields;
- table->file->ha_set_all_bits_in_read_set();
+ 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,
+ while in the case of views, the fields considered as used are the
+ ones marked in setup_tables during fix_fields of view columns.
+ For NATURAL joins, used_tables is updated in the IF above.
+ */
+ if (table)
+ table->used_fields= table->s->fields;
}
if (found)
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
+ /*
+ TODO: in the case when we skipped all columns because there was a
+ qualified '*', and all columns were coalesced, we have to give a more
+ meaningful message than ER_BAD_TABLE_ERROR.
+ */
if (!table_name)
my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
else
my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
-err:
- DBUG_RETURN(1);
+
+ DBUG_RETURN(TRUE);
}
/*
- Fix all conditions and outer join expressions
+ Fix all conditions and outer join expressions.
SYNOPSIS
setup_conds()
thd thread handler
- leaves list of leaves of join table tree
+ tables list of tables for name resolving (select_lex->table_list)
+ leaves list of leaves of join table tree (select_lex->leaf_tables)
+ conds WHERE clause
+
+ DESCRIPTION
+ TODO
+
+ RETURN
+ TRUE if some error occured (e.g. out of memory)
+ FALSE if all is OK
*/
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
@@ -3695,6 +4527,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
arena= 0; // For easier test
thd->set_query_id=1;
+ select_lex->cond_count= 0;
for (table= tables; table; table= table->next_local)
{
@@ -3702,7 +4535,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
goto err_no_arena;
}
- select_lex->cond_count= 0;
if (*conds)
{
thd->where="where clause";
@@ -3711,11 +4543,14 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
goto err_no_arena;
}
- /* Check if we are using outer joins */
+ /*
+ Apply fix_fields() to all ON clauses at all levels of nesting,
+ including the ones inside view definitions.
+ */
for (table= leaves; table; table= table->next_leaf)
{
- TABLE_LIST *embedded;
- TABLE_LIST *embedding= table;
+ TABLE_LIST *embedded; /* The table at the current level of nesting. */
+ TABLE_LIST *embedding= table; /* The parent nested table reference. */
do
{
embedded= embedding;
@@ -3729,146 +4564,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
goto err_no_arena;
select_lex->cond_count++;
}
-
- if (embedded->natural_join)
- {
- /* Make a join of all fields wich have the same name */
- TABLE_LIST *tab1= embedded;
- TABLE_LIST *tab2= embedded->natural_join;
- if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
- {
- while (tab1->nested_join)
- {
- TABLE_LIST *next;
- List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
- tab1= it++;
- while ((next= it++))
- tab1= next;
- }
- }
- else
- {
- while (tab1->nested_join)
- tab1= tab1->nested_join->join_list.head();
- }
- if (embedded->outer_join & JOIN_TYPE_RIGHT)
- {
- while (tab2->nested_join)
- {
- TABLE_LIST *next;
- List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
- tab2= it++;
- while ((next= it++))
- tab2= next;
- }
- }
- else
- {
- while (tab2->nested_join)
- tab2= tab2->nested_join->join_list.head();
- }
-
- if (arena)
- arena= thd->change_arena_if_needed(&backup);
-
- TABLE *t1=tab1->table;
- TABLE *t2=tab2->table;
- Field_iterator_table table_iter;
- Field_iterator_view view_iter;
- Field_iterator *iterator;
- Field *t1_field, *t2_field;
- Item *item_t2= 0;
- Item_cond_and *cond_and= new Item_cond_and();
-
- if (!cond_and) // If not out of memory
- goto err_no_arena;
- cond_and->top_level_item();
-
- if (table->field_translation)
- {
- iterator= &view_iter;
- view_iter.set(tab1);
- }
- else
- {
- iterator= &table_iter;
- table_iter.set(tab1);
- }
-
- for (; !iterator->end_of_fields(); iterator->next())
- {
- const char *t1_field_name= iterator->name();
- uint not_used_field_index= NO_CACHED_FIELD_INDEX;
-
- if ((t2_field= find_field_in_table(thd, tab2, t1_field_name,
- t1_field_name,
- strlen(t1_field_name), &item_t2,
- 0, 0, 0,
- &not_used_field_index,
- FALSE)))
- {
- if (t2_field != view_ref_found)
- {
- if (!(item_t2= new Item_field(thd, &select_lex->context,
- t2_field)))
- goto err;
- /* Mark field used for table cache */
- t2_field->query_id= thd->query_id;
- t2->file->ha_set_bit_in_read_set(t2_field->fieldnr);
- t2->used_keys.intersect(t2_field->part_of_key);
- }
- if ((t1_field= iterator->field()))
- {
- /* Mark field used for table cache */
- t1_field->query_id= thd->query_id;
- t1->file->ha_set_bit_in_read_set(t1_field->fieldnr);
- t1->used_keys.intersect(t1_field->part_of_key);
- }
- Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd),
- item_t2);
- if (!tmp)
- goto err;
- cond_and->list.push_back(tmp);
- }
- }
- select_lex->cond_count+= cond_and->list.elements;
-
- // to prevent natural join processing during PS re-execution
- embedding->natural_join= 0;
-
- if (cond_and->list.elements)
- {
- COND *on_expr= cond_and;
- if (!on_expr->fixed)
- on_expr->fix_fields(thd, &on_expr);
- if (!embedded->outer_join) // Not left join
- {
- *conds= and_conds(*conds, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (*conds && !(*conds)->fixed)
- {
- if ((*conds)->fix_fields(thd, conds))
- goto err_no_arena;
- }
- }
- else
- {
- embedded->on_expr= and_conds(embedded->on_expr, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (embedded->on_expr && !embedded->on_expr->fixed)
- {
- if (embedded->on_expr->fix_fields(thd, &embedded->on_expr))
- goto err_no_arena;
- }
- }
- }
- else if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- }
embedding= embedded->embedding;
}
while (embedding &&
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index d03d4c381fa..8cfeb4be024 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -762,7 +762,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
TABLE_COUNTER_TYPE local_tables;
ulong tot_length;
DBUG_ENTER("Query_cache::store_query");
- if (query_cache_size == 0)
+ if (query_cache_size == 0 || thd->locked_tables)
DBUG_VOID_RETURN;
uint8 tables_type= 0;
@@ -923,6 +923,10 @@ end:
0 The query was cached and user was sent the result.
-1 The query was cached but we didn't have rights to use it.
No error is sent to the client yet.
+
+ NOTE
+ This method requires that sql points to allocated memory of size:
+ tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
*/
int
@@ -936,8 +940,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_query_flags flags;
DBUG_ENTER("Query_cache::send_result_to_client");
- if (query_cache_size == 0 || thd->variables.query_cache_type == 0)
-
+ if (query_cache_size == 0 || thd->locked_tables ||
+ thd->variables.query_cache_type == 0)
goto err;
/* Check that we haven't forgot to reset the query cache variables */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 56d3194765b..d4f05456cad 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -157,8 +157,8 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
-Open_tables_state::Open_tables_state()
- :version(refresh_version)
+Open_tables_state::Open_tables_state(ulong version_arg)
+ :version(version_arg)
{
reset_open_tables_state();
}
@@ -172,9 +172,9 @@ Open_tables_state::Open_tables_state()
THD::THD()
:Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
- Open_tables_state(),
+ Open_tables_state(refresh_version),
lock_id(&main_lock_id),
- user_time(0), in_sub_stmt(FALSE), global_read_lock(0), is_fatal_error(0),
+ user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
@@ -323,7 +323,8 @@ void THD::init_for_queries()
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
#endif
- transaction.xid.null();
+ transaction.xid_state.xid.null();
+ transaction.xid_state.in_thd=1;
}
@@ -358,9 +359,15 @@ void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
- if (transaction.xa_state != XA_PREPARED)
+ if (transaction.xid_state.xa_state == XA_PREPARED)
+ {
+#error xid_state in the cache should be replaced by the allocated value
+ }
#endif
+ {
ha_rollback(this);
+ xid_cache_delete(&transaction.xid_state);
+ }
if (locked_tables)
{
lock=locked_tables; locked_tables=0;
@@ -1813,31 +1820,195 @@ void THD::set_status_var_init()
access to mysql.proc table to find definitions of stored routines.
****************************************************************************/
-bool THD::push_open_tables_state()
+void THD::reset_n_backup_open_tables_state(Open_tables_state *backup)
{
- Open_tables_state *state;
- DBUG_ENTER("push_open_table_state");
- /* Currently we only push things one level */
- DBUG_ASSERT(open_state_list.elements == 0);
-
- if (!(state= (Open_tables_state*) alloc(sizeof(*state))))
- DBUG_RETURN(1); // Fatal error is set
- /* Store state for currently open tables */
- state->set_open_tables_state(this);
- if (open_state_list.push_back(state, mem_root))
- DBUG_RETURN(1); // Fatal error is set
+ DBUG_ENTER("reset_n_backup_open_tables_state");
+ backup->set_open_tables_state(this);
reset_open_tables_state();
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
-void THD::pop_open_tables_state()
-{
- Open_tables_state *state;
- DBUG_ENTER("pop_open_table_state");
- /* Currently we only push things one level */
- DBUG_ASSERT(open_state_list.elements == 1);
- state= open_state_list.pop();
- set_open_tables_state(state);
+void THD::restore_backup_open_tables_state(Open_tables_state *backup)
+{
+ DBUG_ENTER("restore_backup_open_tables_state");
+ /*
+ Before we will throw away current open tables state we want
+ to be sure that it was properly cleaned up.
+ */
+ DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
+ handler_tables == 0 && derived_tables == 0 &&
+ lock == 0 && locked_tables == 0 &&
+ prelocked_mode == NON_PRELOCKED);
+ set_open_tables_state(backup);
DBUG_VOID_RETURN;
}
+
+
+
+/****************************************************************************
+ Handling of statement states in functions and triggers.
+
+ This is used to ensure that the function/trigger gets a clean state
+ to work with and does not cause any side effects of the calling statement.
+
+ It also allows most stored functions and triggers to replicate even
+ if they are used items that would normally be stored in the binary
+ replication (like last_insert_id() etc...)
+
+ The following things is done
+ - Disable binary logging for the duration of the statement
+ - Disable multi-result-sets for the duration of the statement
+ - Value of last_insert_id() is reset and restored
+ - Value set by 'SET INSERT_ID=#' is reset and restored
+ - Value for found_rows() is reset and restored
+ - examined_row_count is added to the total
+ - cuted_fields is added to the total
+
+ NOTES:
+ Seed for random() is saved for the first! usage of RAND()
+ We reset examined_row_count and cuted_fields and add these to the
+ result to ensure that if we have a bug that would reset these within
+ a function, we are not loosing any rows from the main statement.
+****************************************************************************/
+
+void THD::reset_sub_statement_state(Sub_statement_state *backup,
+ uint new_state)
+{
+ backup->options= options;
+ backup->in_sub_stmt= in_sub_stmt;
+ backup->no_send_ok= net.no_send_ok;
+ backup->enable_slow_log= enable_slow_log;
+ backup->last_insert_id= last_insert_id;
+ backup->next_insert_id= next_insert_id;
+ backup->insert_id_used= insert_id_used;
+ backup->limit_found_rows= limit_found_rows;
+ backup->examined_row_count= examined_row_count;
+ backup->sent_row_count= sent_row_count;
+ backup->cuted_fields= cuted_fields;
+ backup->client_capabilities= client_capabilities;
+
+ options&= ~OPTION_BIN_LOG;
+ /* Disable result sets */
+ client_capabilities &= ~CLIENT_MULTI_RESULTS;
+ in_sub_stmt|= new_state;
+ last_insert_id= 0;
+ next_insert_id= 0;
+ insert_id_used= 0;
+ examined_row_count= 0;
+ sent_row_count= 0;
+ cuted_fields= 0;
+
+#ifndef EMBEDDED_LIBRARY
+ /* Surpress OK packets in case if we will execute statements */
+ net.no_send_ok= TRUE;
+#endif
+}
+
+
+void THD::restore_sub_statement_state(Sub_statement_state *backup)
+{
+ options= backup->options;
+ in_sub_stmt= backup->in_sub_stmt;
+ net.no_send_ok= backup->no_send_ok;
+ enable_slow_log= backup->enable_slow_log;
+ last_insert_id= backup->last_insert_id;
+ next_insert_id= backup->next_insert_id;
+ insert_id_used= backup->insert_id_used;
+ limit_found_rows= backup->limit_found_rows;
+ sent_row_count= backup->sent_row_count;
+ client_capabilities= backup->client_capabilities;
+
+ /*
+ The following is added to the old values as we are interested in the
+ total complexity of the query
+ */
+ examined_row_count+= backup->examined_row_count;
+ cuted_fields+= backup->cuted_fields;
+}
+
+
+/***************************************************************************
+ Handling of XA id cacheing
+***************************************************************************/
+
+pthread_mutex_t LOCK_xid_cache;
+HASH xid_cache;
+
+static byte *xid_get_hash_key(const byte *ptr,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=((XID_STATE*)ptr)->xid.length();
+ return (byte *)&((XID_STATE*)ptr)->xid;
+}
+
+static void xid_free_hash (void *ptr)
+{
+ if (!((XID_STATE*)ptr)->in_thd)
+ my_free((byte *)ptr, MYF(0));
+}
+
+bool xid_cache_init()
+{
+ pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST);
+ return hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
+ xid_get_hash_key, xid_free_hash, 0) != 0;
+}
+
+void xid_cache_free()
+{
+ if (hash_inited(&xid_cache))
+ {
+ hash_free(&xid_cache);
+ pthread_mutex_destroy(&LOCK_xid_cache);
+ }
+}
+
+XID_STATE *xid_cache_search(XID *xid)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, (byte *)xid, xid->length());
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+
+bool xid_cache_insert(XID *xid, enum xa_states xa_state)
+{
+ XID_STATE *xs;
+ my_bool res;
+ pthread_mutex_lock(&LOCK_xid_cache);
+ if (hash_search(&xid_cache, (byte *)xid, xid->length()))
+ res=0;
+ else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
+ res=1;
+ else
+ {
+ xs->xa_state=xa_state;
+ xs->xid.set(xid);
+ xs->in_thd=0;
+ res=my_hash_insert(&xid_cache, (byte*)xs);
+ }
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+
+bool xid_cache_insert(XID_STATE *xid_state)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ DBUG_ASSERT(hash_search(&xid_cache, (byte *)&xid_state->xid,
+ xid_state->xid.length())==0);
+ my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state);
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+
+void xid_cache_delete(XID_STATE *xid_state)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ hash_delete(&xid_cache, (byte *)xid_state);
+ pthread_mutex_unlock(&LOCK_xid_cache);
+}
+
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d2aea640245..a1de3391ab4 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -351,8 +351,6 @@ public:
inline uint32 get_open_count() { return open_count; }
};
-/* character conversion tables */
-
typedef struct st_copy_info {
ha_rows records;
@@ -566,11 +564,11 @@ struct system_variables
#endif /* HAVE_NDBCLUSTER_DB */
my_bool old_alter_table;
my_bool old_passwords;
-
+
/* Only charset part of these variables is sensible */
- CHARSET_INFO *character_set_client;
+ CHARSET_INFO *character_set_client;
CHARSET_INFO *character_set_results;
-
+
/* Both charset and collation parts of these variables are important */
CHARSET_INFO *collation_server;
CHARSET_INFO *collation_database;
@@ -633,7 +631,7 @@ typedef struct system_status_var
ulong filesort_range_count;
ulong filesort_rows;
ulong filesort_scan_count;
- /* Ppepared statements and binary protocol */
+ /* Prepared statements and binary protocol */
ulong com_stmt_prepare;
ulong com_stmt_execute;
ulong com_stmt_send_long_data;
@@ -658,8 +656,8 @@ void free_tmp_table(THD *thd, TABLE *entry);
/* The following macro is to make init of Query_arena simpler */
#ifndef DBUG_OFF
#define INIT_ARENA_DBUG_INFO is_backup_arena= 0
-#else
-#define INIT_ARENA_DBUG_INFO
+#else
+#define INIT_ARENA_DBUG_INFO
#endif
@@ -934,6 +932,22 @@ struct st_savepoint {
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
extern const char *xa_state_names[];
+typedef struct st_xid_state {
+ /* For now, this is only used to catch duplicated external xids */
+ XID xid; // transaction identifier
+ enum xa_states xa_state; // used by external XA only
+ bool in_thd;
+} XID_STATE;
+
+extern pthread_mutex_t LOCK_xid_cache;
+extern HASH xid_cache;
+bool xid_cache_init(void);
+void xid_cache_free(void);
+XID_STATE *xid_cache_search(XID *xid);
+bool xid_cache_insert(XID *xid, enum xa_states xa_state);
+bool xid_cache_insert(XID_STATE *xid_state);
+void xid_cache_delete(XID_STATE *xid_state);
+
/*
A registry for item tree transformations performed during
query optimization. We register only those changes which require
@@ -955,7 +969,7 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
/*
- Class that holds information about tables which were open and locked
+ Class that holds information about tables which were opened and locked
by the thread. It is also used to save/restore this information in
push_open_tables_state()/pop_open_tables_state().
*/
@@ -1018,7 +1032,13 @@ public:
ulong version;
uint current_tablenr;
- Open_tables_state();
+ /*
+ This constructor serves for creation of Open_tables_state instances
+ which are used as backup storage.
+ */
+ Open_tables_state() {};
+
+ Open_tables_state(ulong version_arg);
void set_open_tables_state(Open_tables_state *state)
{
@@ -1034,6 +1054,27 @@ public:
};
+/* class to save context when executing a function or trigger */
+
+/* Defines used for Sub_statement_state::in_sub_stmt */
+
+#define SUB_STMT_TRIGGER 1
+#define SUB_STMT_FUNCTION 2
+
+class Sub_statement_state
+{
+public:
+ ulonglong options;
+ ulonglong last_insert_id, next_insert_id;
+ ulonglong limit_found_rows;
+ ha_rows cuted_fields, sent_row_count, examined_row_count;
+ ulong client_capabilities;
+ uint in_sub_stmt;
+ bool enable_slow_log, insert_id_used;
+ my_bool no_send_ok;
+};
+
+
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1071,7 +1112,7 @@ public:
// the lock_id of a cursor.
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/* all prepared statements and cursors of this connection */
- Statement_map stmt_map;
+ Statement_map stmt_map;
/*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
@@ -1140,11 +1181,10 @@ public:
time_t connect_time,thr_create_time; // track down slow pthread_create
thr_lock_type update_lock_default;
delayed_insert *di;
- my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
-
- /* TRUE if we are inside of trigger or stored function. */
- bool in_sub_stmt;
-
+
+ /* <> 0 if we are inside of trigger or stored function. */
+ uint in_sub_stmt;
+
/* container for handler's private per-connection data */
void *ha_data[MAX_HA];
struct st_transactions {
@@ -1152,8 +1192,7 @@ public:
THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement
bool on; // see ha_enable_transaction()
- XID xid; // transaction identifier
- enum xa_states xa_state; // used by external XA only
+ XID_STATE xid_state;
/*
Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query
@@ -1173,7 +1212,7 @@ public:
st_transactions()
{
bzero((char*)this, sizeof(*this));
- xid.null();
+ xid_state.xid.null();
init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
}
#endif
@@ -1226,8 +1265,16 @@ public:
*/
ulonglong current_insert_id;
ulonglong limit_found_rows;
+ ulonglong options; /* Bitmap of states */
+ longlong row_count_func; /* For the ROW_COUNT() function */
ha_rows cuted_fields,
sent_row_count, examined_row_count;
+ /*
+ The set of those tables whose fields are referenced in all subqueries
+ of the query.
+ TODO: possibly this it is incorrect to have used tables in THD because
+ with more than one subquery, it is not clear what does the field mean.
+ */
table_map used_tables;
USER_CONN *user_connect;
CHARSET_INFO *db_charset;
@@ -1240,7 +1287,6 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
- List <Open_tables_state> open_state_list;
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
@@ -1250,7 +1296,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id, warn_id;
- ulong options, thread_id, col_access;
+ ulong thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
@@ -1290,7 +1336,8 @@ public:
bool no_warnings_for_error; /* no warnings on call to my_error() */
/* set during loop of derived table processing */
bool derived_tables_processing;
- longlong row_count_func; /* For the ROW_COUNT() function */
+ my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
+
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
@@ -1496,13 +1543,15 @@ public:
void set_status_var_init();
bool is_context_analysis_only()
{ return current_arena->is_stmt_prepare() || lex->view_prepare_mode; }
- bool push_open_tables_state();
- void pop_open_tables_state();
+ void reset_n_backup_open_tables_state(Open_tables_state *backup);
+ void restore_backup_open_tables_state(Open_tables_state *backup);
+ void reset_sub_statement_state(Sub_statement_state *backup, uint new_state);
+ void restore_sub_statement_state(Sub_statement_state *backup);
};
#define tmp_disable_binlog(A) \
- {ulong tmp_disable_binlog__save_options= (A)->options; \
+ {ulonglong tmp_disable_binlog__save_options= (A)->options; \
(A)->options&= ~OPTION_BIN_LOG
#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
@@ -1569,6 +1618,7 @@ public:
statement/stored procedure.
*/
virtual void cleanup();
+ void set_thd(THD *thd_arg) { thd= thd_arg; }
};
@@ -1924,14 +1974,13 @@ class multi_delete :public select_result_interceptor
{
TABLE_LIST *delete_tables, *table_being_deleted;
Unique **tempfiles;
- THD *thd;
ha_rows deleted, found;
uint num_of_tables;
int error;
bool do_delete, transactional_tables, normal_tables, delete_while_scanning;
public:
- multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
+ multi_delete(TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
@@ -1947,7 +1996,6 @@ class multi_update :public select_result_interceptor
TABLE_LIST *all_tables; /* query/update command tables */
TABLE_LIST *leaves; /* list of leves of join table tree */
TABLE_LIST *update_tables, *table_being_updated;
- THD *thd;
TABLE **tmp_tables, *main_table, *table_to_update;
TMP_TABLE_PARAM *tmp_table_param;
ha_rows updated, found;
@@ -1959,7 +2007,7 @@ class multi_update :public select_result_interceptor
bool do_update, trans_safe, transactional_tables, ignore;
public:
- multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,
+ multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list,
List<Item> *fields, List<Item> *values,
enum_duplicates handle_duplicates, bool ignore);
~multi_update();
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index d110ff6f778..5ca3f07f0bd 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -26,13 +26,16 @@
#include <direct.h>
#endif
+#define MAX_DROP_TABLE_Q_LEN 1024
+
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
- const char *db, const char *path,
- uint level);
+ const char *db, const char *path, uint level,
+ TABLE_LIST **dropped_tables);
+
static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
/* Database options hash */
@@ -52,6 +55,7 @@ typedef struct my_dbopt_st
/*
Function we use in the creation of our hash to get key.
*/
+
static byte* dboptions_get_key(my_dbopt_t *opt, uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -61,6 +65,21 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length,
/*
+ Helper function to write a query to binlog used by mysql_rm_db()
+*/
+
+static inline void write_to_binlog(THD *thd, char *query, uint q_len,
+ char *db, uint db_len)
+{
+ Query_log_event qinfo(thd, query, q_len, 0, 0);
+ qinfo.error_code= 0;
+ qinfo.db= db;
+ qinfo.db_len= db_len;
+ mysql_bin_log.write(&qinfo);
+}
+
+
+/*
Function to free dboptions hash element
*/
@@ -593,6 +612,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
char path[FN_REFLEN+16];
MY_DIR *dirp;
uint length;
+ TABLE_LIST* dropped_tables= 0;
DBUG_ENTER("mysql_rm_db");
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
@@ -629,8 +649,10 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
remove_db_from_cache(db);
pthread_mutex_unlock(&LOCK_open);
+
error= -1;
- if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0)) >= 0)
+ if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
+ &dropped_tables)) >= 0)
{
ha_drop_database(path);
query_cache_invalidate1(db);
@@ -672,6 +694,43 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
send_ok(thd, (ulong) deleted);
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
}
+ else if (mysql_bin_log.is_open())
+ {
+ char *query, *query_pos, *query_end, *query_data_start;
+ TABLE_LIST *tbl;
+ uint db_len;
+
+ if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN)))
+ goto exit; /* not much else we can do */
+ query_pos= query_data_start= strmov(query,"drop table ");
+ query_end= query + MAX_DROP_TABLE_Q_LEN;
+ db_len= strlen(db);
+
+ for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
+ {
+ uint tbl_name_len;
+ if (!tbl->was_dropped)
+ continue;
+
+ /* 3 for the quotes and the comma*/
+ tbl_name_len= strlen(tbl->table_name) + 3;
+ if (query_pos + tbl_name_len + 1 >= query_end)
+ {
+ write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
+ query_pos= query_data_start;
+ }
+
+ *query_pos++ = '`';
+ query_pos= strmov(query_pos,tbl->table_name);
+ *query_pos++ = '`';
+ *query_pos++ = ',';
+ }
+
+ if (query_pos != query_data_start)
+ {
+ write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
+ }
+ }
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
@@ -717,7 +776,8 @@ exit2:
*/
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
- const char *org_path, uint level)
+ const char *org_path, uint level,
+ TABLE_LIST **dropped_tables)
{
long deleted=0;
ulong found_other_files=0;
@@ -759,7 +819,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
{
DBUG_PRINT("my",("New subdir found: %s", newpath));
- if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0)
+ if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
goto err;
if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
!(dir= new (thd->mem_root) String(copy_of_path, length,
@@ -837,6 +897,9 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
}
my_dirend(dirp);
+ if (dropped_tables)
+ *dropped_tables= tot_list;
+
/*
If the directory is a symbolic link, remove the link first, then
remove the directory the symbolic link pointed at
@@ -996,8 +1059,9 @@ err:
SYNOPSIS
mysql_change_db()
- thd Thread handler
- name Databasename
+ thd Thread handler
+ name Databasename
+ no_access_check True don't do access check. In this case name may be ""
DESCRIPTION
Becasue the database name may have been given directly from the
@@ -1009,28 +1073,37 @@ err:
replication slave SQL thread (for that thread, setting of thd->db is done
in ::exec_event() methods of log_event.cc).
- This function does not send the error message to the client, if that
- should be sent to the client, call net_send_error after this function
+ This function does not send anything, including error messages to the
+ client, if that should be sent to the client, call net_send_error after
+ this function.
RETURN VALUES
0 ok
1 error
*/
-bool mysql_change_db(THD *thd, const char *name)
+bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
{
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
HA_CREATE_INFO create;
- bool schema_db= 0;
+ bool system_db= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
#endif
DBUG_ENTER("mysql_change_db");
+ DBUG_PRINT("enter",("name: '%s'",name));
+ /* dbname can only be NULL if malloc failed */
if (!dbname || !(db_length= strlen(dbname)))
{
+ if (no_access_check && dbname)
+ {
+ /* Called from SP when orignal database was not set */
+ system_db= 1;
+ goto end;
+ }
x_free(dbname); /* purecov: inspected */
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
MYF(0)); /* purecov: inspected */
@@ -1045,7 +1118,7 @@ bool mysql_change_db(THD *thd, const char *name)
DBUG_PRINT("info",("Use database: %s", dbname));
if (!my_strcasecmp(system_charset_info, dbname, information_schema_name.str))
{
- schema_db= 1;
+ system_db= 1;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= SELECT_ACL;
#endif
@@ -1053,23 +1126,27 @@ bool mysql_change_db(THD *thd, const char *name)
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (test_all_bits(thd->master_access,DB_ACLS))
- db_access=DB_ACLS;
- else
- db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
- thd->master_access);
- if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ if (!no_access_check)
{
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user,
- thd->priv_host,
- dbname);
- mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- thd->priv_user,
- thd->priv_host,
- dbname);
- my_free(dbname,MYF(0));
- DBUG_RETURN(1);
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) && (!grant_option ||
+ check_grant_db(thd,dbname)))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
}
#endif
(void) sprintf(path,"%s/%s",mysql_data_home,dbname);
@@ -1083,14 +1160,14 @@ bool mysql_change_db(THD *thd, const char *name)
DBUG_RETURN(1);
}
end:
- send_ok(thd);
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- thd->db_access=db_access;
+ if (!no_access_check)
+ thd->db_access=db_access;
#endif
- if (schema_db)
+ if (system_db)
{
thd->db_charset= system_charset_info;
thd->variables.collation_database= system_charset_info;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 2967e2a8a20..5c339d7d64d 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -30,7 +30,7 @@
#include "sql_trigger.h"
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- SQL_LIST *order, ha_rows limit, ulong options)
+ SQL_LIST *order, ha_rows limit, ulonglong options)
{
bool will_batch;
int error, loc_error;
@@ -309,6 +309,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_ENTER("mysql_prepare_delete");
if (setup_tables(thd, &thd->lex->select_lex.context,
+ &thd->lex->select_lex.top_join_list,
table_list, conds, &select_lex->leaf_tables,
FALSE) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
@@ -367,6 +368,7 @@ 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))
DBUG_RETURN(TRUE);
@@ -415,9 +417,8 @@ bool mysql_multi_delete_prepare(THD *thd)
}
-multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
- uint num_of_tables_arg)
- : delete_tables(dt), thd(thd_arg), deleted(0), found(0),
+multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
+ : delete_tables(dt), deleted(0), found(0),
num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), normal_tables(0)
{
@@ -826,7 +827,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
ha_enable_transaction(thd, FALSE);
mysql_init_select(thd->lex);
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
- HA_POS_ERROR, 0);
+ HA_POS_ERROR, LL(0));
ha_enable_transaction(thd, TRUE);
thd->options= save_options;
DBUG_RETURN(error);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index fc9d15e94c4..7b9191cd841 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -125,6 +125,11 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias)))
goto exit;
+ if (check_duplicate_names(unit->types, 0))
+ {
+ res= -1;
+ goto exit;
+ }
derived_result->tmp_table_param.init();
derived_result->tmp_table_param.field_count= unit->types.elements;
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 84087db9719..fc7d7ac0012 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -187,7 +187,7 @@ 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);
+ error= open_tables(thd, &tables, &counter, 0);
HANDLER_TABLES_HACK(thd);
if (error)
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 11045529a51..e3a2602713f 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -75,7 +75,7 @@ enum enum_used_fields
RETURN VALUES
0 all ok
- 1 one of the fileds didn't finded
+ 1 one of the fileds was not found
*/
static bool init_fields(THD *thd, TABLE_LIST *tables,
@@ -90,7 +90,7 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
Item_field *field= new Item_field(context,
"mysql", find_fields->table_name,
find_fields->field_name);
- if (!(find_fields->field= find_field_in_tables(thd, field, tables,
+ if (!(find_fields->field= find_field_in_tables(thd, field, tables, NULL,
0, REPORT_ALL_ERRORS, 1,
TRUE)))
DBUG_RETURN(1);
@@ -623,43 +623,45 @@ bool mysqld_help(THD *thd, const char *mask)
Protocol *protocol= thd->protocol;
SQL_SELECT *select;
st_find_field used_fields[array_elements(init_used_fields)];
- DBUG_ENTER("mysqld_help");
-
TABLE_LIST *leaves= 0;
TABLE_LIST tables[4];
+ List<String> topics_list, categories_list, subcategories_list;
+ String name, description, example;
+ int count_topics, count_categories, error;
+ uint mlen= strlen(mask);
+ size_t i;
+ MEM_ROOT *mem_root= thd->mem_root;
+ DBUG_ENTER("mysqld_help");
+
bzero((gptr)tables,sizeof(tables));
tables[0].alias= tables[0].table_name= (char*) "help_topic";
tables[0].lock_type= TL_READ;
- tables[0].next_global= tables[0].next_local= &tables[1];
+ tables[0].next_global= tables[0].next_local=
+ tables[0].next_name_resolution_table= &tables[1];
tables[1].alias= tables[1].table_name= (char*) "help_category";
tables[1].lock_type= TL_READ;
- tables[1].next_global= tables[1].next_local= &tables[2];
+ tables[1].next_global= tables[1].next_local=
+ tables[1].next_name_resolution_table= &tables[2];
tables[2].alias= tables[2].table_name= (char*) "help_relation";
tables[2].lock_type= TL_READ;
- tables[2].next_global= tables[2].next_local= &tables[3];
+ tables[2].next_global= tables[2].next_local=
+ tables[2].next_name_resolution_table= &tables[3];
tables[3].alias= tables[3].table_name= (char*) "help_keyword";
tables[3].lock_type= TL_READ;
tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
- List<String> topics_list, categories_list, subcategories_list;
- String name, description, example;
- int count_topics, count_categories, error;
- uint mlen= strlen(mask);
- MEM_ROOT *mem_root= thd->mem_root;
-
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);
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
goto error;
- size_t i;
for (i=0; i<sizeof(tables)/sizeof(TABLE_LIST); i++)
tables[i].table->file->init_table_handle_for_HANDLER();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 6e83017a4e4..869ae688e34 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -111,12 +111,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
else
{ // Part field list
- Name_resolution_context *context= &thd->lex->select_lex.context;
- TABLE_LIST *save_next= table_list->next_local,
- *save_context= context->table_list;
- bool save_resolve_in_select_list=
- thd->lex->select_lex.context.resolve_in_select_list;
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
+ Name_resolution_context *context= &select_lex->context;
+ TABLE_LIST *save_next_local;
+ TABLE_LIST *save_table_list;
+ TABLE_LIST *save_first_name_resolution_table;
+ TABLE_LIST *save_next_name_resolution_table;
+ bool save_resolve_in_select_list;
int res;
+
if (fields.elements != values.elements)
{
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
@@ -124,8 +127,22 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
thd->dupp_field=0;
- thd->lex->select_lex.no_wrap_view_item= TRUE;
- /* fields only from first table */
+ select_lex->no_wrap_view_item= TRUE;
+
+ /* Save the state of the current name resolution context. */
+ save_table_list= context->table_list;
+ save_first_name_resolution_table= context->first_name_resolution_table;
+ save_next_name_resolution_table= (context->first_name_resolution_table) ?
+ context->first_name_resolution_table->
+ next_name_resolution_table :
+ NULL;
+ save_resolve_in_select_list= context->resolve_in_select_list;
+ save_next_local= table_list->next_local;
+
+ /*
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
/*
@@ -133,12 +150,20 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
parameter to 2. This sets the bit in the write_set for each field.
*/
res= setup_fields(thd, 0, fields, 2, 0, 0);
- table_list->next_local= save_next;
+
+ /* Restore the current context. */
+ table_list->next_local= save_next_local;
+ context->table_list= save_table_list;
+ context->first_name_resolution_table= save_first_name_resolution_table;
+ if (context->first_name_resolution_table)
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_name_resolution_table;
+ context->resolve_in_select_list= save_resolve_in_select_list;
thd->lex->select_lex.no_wrap_view_item= FALSE;
- context->table_list= save_context;
- context->resolve_in_select_list= save_resolve_in_select_list;
+
if (res)
return -1;
+
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
/* it is join view => we need to find table for update */
@@ -267,9 +292,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
ulonglong id;
COPY_INFO info;
TABLE *table= 0;
- TABLE_LIST *next_local;
+ TABLE_LIST *save_table_list;
+ TABLE_LIST *save_next_local;
+ TABLE_LIST *save_first_name_resolution_table;
+ TABLE_LIST *save_next_name_resolution_table;
List_iterator_fast<List_item> its(values_list);
List_item *values;
+ Name_resolution_context *context;
#ifndef EMBEDDED_LIBRARY
char *query= thd->query;
#endif
@@ -348,9 +377,23 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* mysql_prepare_insert set table_list->table if it was not set */
table= table_list->table;
- next_local= table_list->next_local;
+ context= &thd->lex->select_lex.context;
+ /* Save the state of the current name resolution context. */
+ save_table_list= context->table_list;
+ save_first_name_resolution_table= context->first_name_resolution_table;
+ save_next_name_resolution_table= (context->first_name_resolution_table) ?
+ context->first_name_resolution_table->
+ next_name_resolution_table :
+ NULL;
+ save_next_local= table_list->next_local;
+
+ /*
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
table_list->next_local= 0;
- thd->lex->select_lex.context.resolve_in_table_list_only(table_list);
+ context->resolve_in_table_list_only(table_list);
+
value_count= values->elements;
while ((values= its++))
{
@@ -364,7 +407,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
goto abort;
}
its.rewind ();
- table_list->next_local= next_local;
+
+ /* Restore the current context. */
+ table_list->next_local= save_next_local;
+ context->first_name_resolution_table= save_first_name_resolution_table;
+ if (context->first_name_resolution_table)
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_name_resolution_table;
+
/*
Fill in the given fields and dump it to the table file
*/
@@ -720,6 +770,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
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))
DBUG_RETURN(TRUE);
@@ -774,10 +825,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
COND **where, bool select_insert)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
+ Name_resolution_context *context= &select_lex->context;
TABLE_LIST *save_table_list;
TABLE_LIST *save_next_local;
+ TABLE_LIST *save_first_name_resolution_table;
+ TABLE_LIST *save_next_name_resolution_table;
+ bool save_resolve_in_select_list;
bool insert_into_view= (table_list->view != 0);
- bool save_resolve_in_select_list;
bool res= 0;
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
@@ -815,35 +869,58 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
select_insert))
DBUG_RETURN(TRUE);
- save_table_list= select_lex->context.table_list;
- save_resolve_in_select_list= select_lex->context.resolve_in_select_list;
- save_next_local= table_list->next_local;
+ /* Save the state of the current name resolution context. */
+ save_table_list= context->table_list;
+ /* Here first_name_resolution_table points to the first select table. */
+ save_first_name_resolution_table= context->first_name_resolution_table;
+ save_next_name_resolution_table= (context->first_name_resolution_table) ?
+ context->first_name_resolution_table->
+ next_name_resolution_table :
+ NULL;
+ save_resolve_in_select_list= context->resolve_in_select_list;
+ save_next_local= table_list->next_local;
+ /*
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
table_list->next_local= 0;
- select_lex->context.resolve_in_table_list_only(table_list);
- if ((values && check_insert_fields(thd, table_list, fields, *values,
- !insert_into_view)) ||
- (values && setup_fields(thd, 0, *values, 0, 0, 0)))
- res= TRUE;
- else if (duplic == DUP_UPDATE)
+ context->resolve_in_table_list_only(table_list);
+
+ /* Prepare the fields in the statement. */
+ if (values &&
+ !(res= check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view) ||
+ setup_fields(thd, 0, *values, 0, 0, 0)) &&
+ duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, table_list, update_fields);
+ res= check_update_fields(thd, context->table_list, update_fields);
select_lex->no_wrap_view_item= FALSE;
+ /*
+ When we are not using GROUP BY we can refer to other tables in the
+ ON DUPLICATE KEY part.
+ */
if (select_lex->group_list.elements == 0)
{
- /*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part
- */
- table_list->next_local= save_next_local;
+ context->table_list->next_local= save_next_local;
+ /* first_name_resolution_table was set by resolve_in_table_list_only() */
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_local;
}
if (!res)
res= setup_fields(thd, 0, update_values, 1, 0, 0);
}
+
+ /* Restore the current context. */
table_list->next_local= save_next_local;
- select_lex->context.table_list= save_table_list;
- select_lex->context.resolve_in_select_list= save_resolve_in_select_list;
+ context->table_list= save_table_list;
+ context->first_name_resolution_table= save_first_name_resolution_table;
+ if (context->first_name_resolution_table)
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_name_resolution_table;
+ context->resolve_in_select_list= save_resolve_in_select_list;
+
if (res)
DBUG_RETURN(res);
@@ -2102,7 +2179,55 @@ 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);
+ !insert_into_view) ||
+ setup_fields(thd, 0, values, 0, 0, 0);
+
+ if (info.handle_duplicates == DUP_UPDATE)
+ {
+ /* Save the state of the current name resolution context. */
+ Name_resolution_context *context= &lex->select_lex.context;
+ TABLE_LIST *save_table_list;
+ TABLE_LIST *save_next_local;
+ TABLE_LIST *save_first_name_resolution_table;
+ TABLE_LIST *save_next_name_resolution_table;
+ save_table_list= context->table_list;
+ save_first_name_resolution_table= context->first_name_resolution_table;
+ save_next_name_resolution_table= (context->first_name_resolution_table) ?
+ context->first_name_resolution_table->
+ next_name_resolution_table :
+ NULL;
+ save_next_local= table_list->next_local;
+
+ /* Perform name resolution only in the first table - 'table_list'. */
+ table_list->next_local= 0;
+ context->resolve_in_table_list_only(table_list);
+
+ lex->select_lex.no_wrap_view_item= TRUE;
+ res= res || check_update_fields(thd, context->table_list,
+ *info.update_fields);
+ lex->select_lex.no_wrap_view_item= FALSE;
+ /*
+ When we are not using GROUP BY we can refer to other tables in the
+ ON DUPLICATE KEY part
+ */
+ if (lex->select_lex.group_list.elements == 0)
+ {
+ context->table_list->next_local= save_next_local;
+ /* first_name_resolution_table was set by resolve_in_table_list_only() */
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_local;
+ }
+ res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
+
+ /* Restore the current context. */
+ table_list->next_local= save_next_local;
+ context->first_name_resolution_table= save_first_name_resolution_table;
+ if (context->first_name_resolution_table)
+ context->first_name_resolution_table->
+ next_name_resolution_table= save_next_name_resolution_table;
+
+ }
+
lex->current_select= lex_current_select_save;
if (res)
DBUG_RETURN(1);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3fdda5d31a7..9132d3177fc 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -118,8 +118,11 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->buf= lex->ptr= buf;
lex->end_of_query= buf+length;
+ lex->context_stack.empty();
lex->unit.init_query();
lex->unit.init_select();
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+ lex->select_lex.parent_lex= lex;
lex->select_lex.init_query();
lex->value_list.empty();
lex->update_list.empty();
@@ -148,7 +151,6 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->leaf_tables_insert= lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
lex->variables_used= 0;
- lex->select_lex.parent_lex= lex;
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
@@ -1115,6 +1117,11 @@ void st_select_lex::init_query()
having_fix_field= 0;
context.select_lex= this;
context.init();
+ /*
+ Add the name resolution context of the current (sub)query to the
+ stack of contexts for the whole query.
+ */
+ parent_lex->push_context(&context);
cond_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
@@ -1131,7 +1138,7 @@ void st_select_lex::init_select()
{
st_select_lex_node::init_select();
group_list.empty();
- type= db= db1= table1= db2= table2= 0;
+ type= db= 0;
having= 0;
use_index_ptr= ignore_index_ptr= 0;
table_join_options= 0;
@@ -1505,13 +1512,16 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
void st_select_lex_unit::print(String *str)
{
+ bool union_all= !union_distinct;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl != first_select())
{
str->append(" union ", 7);
- if (!union_distinct)
+ if (union_all)
str->append("all ", 4);
+ else if (union_distinct == sl)
+ union_all= TRUE;
}
if (sl->braces)
str->append('(');
@@ -1861,8 +1871,9 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
*/
if ((*link_to_local= test(select_lex.table_list.first)))
{
- select_lex.table_list.first= (byte*) (select_lex.context.table_list=
- first->next_local);
+ select_lex.context.table_list=
+ select_lex.context.first_name_resolution_table= first->next_local;
+ select_lex.table_list.first= (byte*) (first->next_local);
select_lex.table_list.elements--; //safety
first->next_local= 0;
/*
@@ -1967,8 +1978,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
if (link_to_local)
{
first->next_local= (TABLE_LIST*) select_lex.table_list.first;
- select_lex.table_list.first=
- (byte*) (select_lex.context.table_list= first);
+ select_lex.context.table_list= first;
+ select_lex.table_list.first= (byte*) first;
select_lex.table_list.elements++; //safety
}
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 369f0f44ba0..2f29ed4ebd4 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -306,7 +306,7 @@ protected:
*link_next, **link_prev; /* list of whole SELECT_LEX */
public:
- ulong options;
+ ulonglong options;
/*
result of this query can't be cached, bit field, can be :
UNCACHEABLE_DEPENDENT
@@ -459,6 +459,7 @@ public:
inline bool is_prepared() { return prepared; }
bool change_result(select_subselect *result, select_subselect *old_result);
void set_limit(st_select_lex *values);
+ void set_thd(THD *thd_arg) { thd= thd_arg; }
friend void lex_start(THD *thd, uchar *buf, uint length);
friend int subselect_union_engine::exec();
@@ -472,14 +473,16 @@ class st_select_lex: public st_select_lex_node
{
public:
Name_resolution_context context;
- char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
+ char *db;
Item *where, *having; /* WHERE & HAVING clauses */
Item *prep_where; /* saved WHERE clause for prepared statement processing */
/* point on lex in which it was created, used in view subquery detection */
st_lex *parent_lex;
enum olap_type olap;
- SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
- List<Item> item_list; /* list of fields & expressions */
+ /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
+ SQL_LIST table_list;
+ SQL_LIST group_list; /* GROUP BY clause. */
+ List<Item> item_list; /* list of fields & expressions */
List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
/*
@@ -492,7 +495,12 @@ public:
List<TABLE_LIST> top_join_list; /* join list of the top level */
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
TABLE_LIST *embedding; /* table embedding to the above list */
- TABLE_LIST *leaf_tables; /* list of leaves in join table tree */
+ /*
+ Beginning of the list of leaves in a FROM clause, where the leaves
+ inlcude all base tables including view tables. The tables are connected
+ by TABLE_LIST::next_leaf, so leaf_tables points to the left-most leaf.
+ */
+ TABLE_LIST *leaf_tables;
const char *type; /* type of select for EXPLAIN */
SQL_LIST order_list; /* ORDER clause */
@@ -594,7 +602,6 @@ public:
bool init_nested_join(THD *thd);
TABLE_LIST *end_nested_join(THD *thd);
TABLE_LIST *nest_last_join(THD *thd);
- void save_names_for_using_list(TABLE_LIST *tab1, TABLE_LIST *tab2);
void add_joined_table(TABLE_LIST *table);
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
@@ -751,6 +758,21 @@ typedef struct st_lex
List<set_var_base> var_list;
List<Item_param> param_list;
List<LEX_STRING> view_list; // view list (list of field names in view)
+ /*
+ A stack of name resolution contexts for the query. This stack is used
+ at parse time to set local name resolution contexts for various parts
+ of a query. For example, in a JOIN ... ON (some_condition) clause the
+ Items in 'some_condition' must be resolved only against the operands
+ of the the join, and not against the whole clause. Similarly, Items in
+ subqueries should be resolved against the subqueries (and outer queries).
+ The stack is used in the following way: when the parser detects that
+ all Items in some clause need a local context, it creates a new context
+ and pushes it on the stack. All newly created Items always store the
+ top-most context in the stack. Once the parser leaves the clause that
+ required a local context, the parser pops the top-most context.
+ */
+ List<Name_resolution_context> context_stack;
+
SQL_LIST proc_list, auxilliary_table_list, save_list;
create_field *last_field;
udf_func udf;
@@ -942,6 +964,21 @@ typedef struct st_lex
return ( query_tables_own_last ? *query_tables_own_last : 0);
}
void cleanup_after_one_table_open();
+
+ void push_context(Name_resolution_context *context)
+ {
+ context_stack.push_front(context);
+ }
+
+ void pop_context()
+ {
+ context_stack.pop();
+ }
+
+ Name_resolution_context *current_context()
+ {
+ return context_stack.head();
+ }
} LEX;
struct st_lex_local: public st_lex
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 09c01931c38..e4a34cc0aa1 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -426,9 +426,14 @@ struct ilink
template <class T> class I_List_iterator;
+/*
+ WARNING: copy constructor of this class does not create a usable
+ copy, as its members may point at each other.
+*/
+
class base_ilist
{
- public:
+public:
struct ilink *first,last;
inline void empty() { first= &last; last.prev= &first; }
base_ilist() { empty(); }
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 0090f956521..8eec970b4df 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -150,6 +150,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
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))
DBUG_RETURN(-1);
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 71e8fe4149f..b457ff5a6d6 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -153,7 +153,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
List<Item> all_fields(select_lex->item_list);
- if (setup_tables(lex->thd, &select_lex->context,
+ 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) ||
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 341cc84e90c..9fbbee7d8d3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -242,7 +242,8 @@ end:
/*
- Check if user exist and password supplied is correct.
+ Check if user exist and password supplied is correct.
+
SYNOPSIS
check_user()
thd thread handle, thd->{host,user,ip} are used
@@ -277,9 +278,13 @@ int check_user(THD *thd, enum enum_server_command command,
/* Change database if necessary */
if (db && db[0])
{
+ /*
+ thd->db is saved in caller and needs to be freed by caller if this
+ function returns 0
+ */
thd->db= 0;
thd->db_length= 0;
- if (mysql_change_db(thd, db))
+ if (mysql_change_db(thd, db, FALSE))
{
/* Send the error to the client */
net_send_error(thd);
@@ -288,8 +293,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
}
- else
- send_ok(thd);
+ send_ok(thd);
DBUG_RETURN(0);
#else
@@ -414,7 +418,7 @@ int check_user(THD *thd, enum enum_server_command command,
/* Change database if necessary */
if (db && db[0])
{
- if (mysql_change_db(thd, db))
+ if (mysql_change_db(thd, db, FALSE))
{
/* Send error to the client */
net_send_error(thd);
@@ -423,8 +427,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
}
- else
- send_ok(thd);
+ send_ok(thd);
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
@@ -1105,11 +1108,11 @@ pthread_handler_decl(handle_one_connection,arg)
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->query_error)
thd->killed= THD::KILL_CONNECTION;
+ thd->proc_info=0;
+ thd->set_time();
+ thd->init_for_queries();
}
- thd->proc_info=0;
- thd->set_time();
- thd->init_for_queries();
while (!net->error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{
@@ -1219,7 +1222,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
length--;
buff[length]=0;
thd->query_length=length;
- thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
+ thd->query= thd->memdup_w_gap(buff, length+1,
+ thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
thd->query[length] = '\0';
/*
We don't need to obtain LOCK_thread_count here because in bootstrap
@@ -1468,6 +1472,7 @@ bool do_command(THD *thd)
/*
Perform one connection-level (COM_XXXX) command.
+
SYNOPSIS
dispatch_command()
thd connection handle
@@ -1518,8 +1523,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
&LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
- if (!mysql_change_db(thd, tmp.str))
+ if (!mysql_change_db(thd, tmp.str, FALSE))
+ {
mysql_log.write(thd,command,"%s",thd->db);
+ send_ok(thd);
+ }
break;
}
#ifdef HAVE_REPLICATION
@@ -1867,17 +1875,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
case COM_REFRESH:
- {
- statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
- &LOCK_status);
- ulong options= (ulong) (uchar) packet[0];
- if (check_global_access(thd,RELOAD_ACL))
- break;
- mysql_log.write(thd,command,NullS);
- if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
- send_ok(thd);
+ {
+ bool not_used;
+ statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
+ &LOCK_status);
+ ulong options= (ulong) (uchar) packet[0];
+ if (check_global_access(thd,RELOAD_ACL))
break;
- }
+ mysql_log.write(thd,command,NullS);
+ if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
+ send_ok(thd);
+ break;
+ }
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
@@ -2021,7 +2030,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
if (!thd->active_transaction())
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
/* report error issued during command execution */
if (thd->killed_errno() && !thd->net.report_error)
@@ -2047,7 +2056,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
void log_slow_statement(THD *thd)
{
- time_t start_of_query=thd->start_time;
+ time_t start_of_query;
+
+ /*
+ The following should never be true with our current code base,
+ but better to keep this here so we don't accidently try to log a
+ statement in a trigger or stored function
+ */
+ if (unlikely(thd->in_sub_stmt))
+ return; // Don't set time for sub stmt
+
+ start_of_query= thd->start_time;
thd->end_time(); // Set start time
/*
@@ -2138,6 +2157,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
{
TABLE_LIST **query_tables_last= lex->query_tables_last;
sel= new SELECT_LEX();
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+ sel->parent_lex= lex;
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
(List<String> *) 0, (List<String> *) 0))
@@ -2946,8 +2967,8 @@ end_with_restore_list:
*/
if (thd->locked_tables || thd->active_transaction())
{
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION),
- MYF(0));
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
{
@@ -3241,19 +3262,26 @@ end_with_restore_list:
if (!(res= open_and_lock_tables(thd, all_tables)))
{
/* Skip first table, which is the table we are inserting in */
- select_lex->table_list.first= (byte*)first_table->next_local;
-
+ TABLE_LIST *second_table= first_table->next_local;
+ select_lex->table_list.first= (byte*) second_table;
+ select_lex->context.table_list=
+ select_lex->context.first_name_resolution_table= second_table;
res= mysql_insert_select_prepare(thd);
- lex->select_lex.context.table_list= first_table->next_local;
if (!res && (result= new select_insert(first_table, first_table->table,
&lex->field_list,
&lex->update_list,
&lex->value_list,
lex->duplicates, lex->ignore)))
{
- /* Skip first table, which is the table we are inserting in */
- select_lex->context.table_list= first_table->next_local;
-
+ /*
+ Skip first table, which is the table we are inserting in.
+ Below we set context.table_list again because the call above to
+ mysql_insert_select_prepare() calls resolve_in_table_list_only(),
+ which in turn resets context.table_list and
+ context.first_name_resolution_table.
+ */
+ select_lex->context.table_list=
+ select_lex->context.first_name_resolution_table= second_table;
res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
delete result;
}
@@ -3322,7 +3350,7 @@ end_with_restore_list:
if ((res= mysql_multi_delete_prepare(thd)))
goto error;
- if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
+ if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
lex->table_count)))
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
@@ -3411,7 +3439,8 @@ end_with_restore_list:
}
#endif
case SQLCOM_CHANGE_DB:
- mysql_change_db(thd,select_lex->db);
+ if (!mysql_change_db(thd,select_lex->db,FALSE))
+ send_ok(thd);
break;
case SQLCOM_LOAD:
@@ -3642,7 +3671,7 @@ end_with_restore_list:
if (!(res = mysql_create_function(thd, &lex->udf)))
send_ok(thd);
#else
- net_printf_error(thd, ER_CANT_OPEN_LIBRARY, lex->udf.dl, 0, "feature disabled");
+ my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
res= TRUE;
#endif
break;
@@ -3826,13 +3855,13 @@ end_with_restore_list:
lex->no_write_to_binlog= 1;
case SQLCOM_FLUSH:
{
+ bool write_to_binlog;
if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
goto error;
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
*/
- bool write_to_binlog;
if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
{
/*
@@ -4064,8 +4093,8 @@ end_with_restore_list:
name= thd->strdup(name);
db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
res= (result= lex->sphead->create(thd));
- switch (result) {
- case SP_OK:
+ if (result == SP_OK)
+ {
lex->unit.cleanup();
delete lex->sphead;
lex->sphead= 0;
@@ -4085,33 +4114,26 @@ end_with_restore_list:
}
#endif
send_ok(thd);
- break;
- case SP_WRITE_ROW_FAILED:
- my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- goto error;
- case SP_NO_DB_ERROR:
- my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- goto error;
- case SP_BAD_IDENTIFIER:
- my_error(ER_TOO_LONG_IDENT, MYF(0), name);
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- goto error;
- case SP_BODY_TOO_LONG:
- my_error(ER_TOO_LONG_BODY, MYF(0), name);
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- goto error;
- default:
- my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
+ }
+ else
+ {
+ switch (result) {
+ case SP_WRITE_ROW_FAILED:
+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
+ break;
+ case SP_NO_DB_ERROR:
+ my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
+ break;
+ case SP_BAD_IDENTIFIER:
+ my_error(ER_TOO_LONG_IDENT, MYF(0), name);
+ break;
+ case SP_BODY_TOO_LONG:
+ my_error(ER_TOO_LONG_BODY, MYF(0), name);
+ break;
+ default:
+ my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
+ break;
+ }
lex->unit.cleanup();
delete lex->sphead;
lex->sphead= 0;
@@ -4506,14 +4528,15 @@ end_with_restore_list:
break;
}
case SQLCOM_XA_START:
- if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt == XA_RESUME)
{
- if (! thd->transaction.xid.eq(thd->lex->xid))
+ if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
- thd->transaction.xa_state=XA_ACTIVE;
+ thd->transaction.xid_state.xa_state=XA_ACTIVE;
send_ok(thd);
break;
}
@@ -4522,10 +4545,10 @@ end_with_restore_list:
my_error(ER_XAER_INVAL, MYF(0));
break;
}
- if (thd->transaction.xa_state != XA_NOTR)
+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
if (thd->active_transaction() || thd->locked_tables)
@@ -4533,9 +4556,15 @@ end_with_restore_list:
my_error(ER_XAER_OUTSIDE, MYF(0));
break;
}
- DBUG_ASSERT(thd->transaction.xid.is_null());
- thd->transaction.xa_state=XA_ACTIVE;
- thd->transaction.xid.set(thd->lex->xid);
+ if (xid_cache_search(thd->lex->xid))
+ {
+ my_error(ER_XAER_DUPID, MYF(0));
+ break;
+ }
+ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
+ 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)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
@@ -4548,28 +4577,28 @@ end_with_restore_list:
my_error(ER_XAER_INVAL, MYF(0));
break;
}
- if (thd->transaction.xa_state != XA_ACTIVE)
+ if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
- thd->transaction.xa_state=XA_IDLE;
+ thd->transaction.xid_state.xa_state=XA_IDLE;
send_ok(thd);
break;
case SQLCOM_XA_PREPARE:
- if (thd->transaction.xa_state != XA_IDLE)
+ if (thd->transaction.xid_state.xa_state != XA_IDLE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
@@ -4577,22 +4606,28 @@ end_with_restore_list:
if (ha_prepare(thd))
{
my_error(ER_XA_RBROLLBACK, MYF(0));
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
}
- thd->transaction.xa_state=XA_PREPARED;
+ thd->transaction.xid_state.xa_state=XA_PREPARED;
send_ok(thd);
break;
case SQLCOM_XA_COMMIT:
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
- if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1)))
+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
+ if (!xs || xs->in_thd)
my_error(ER_XAER_NOTA, MYF(0));
else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
+ xid_cache_delete(xs);
send_ok(thd);
+ }
break;
}
- if (thd->transaction.xa_state == XA_IDLE &&
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
thd->lex->xa_opt == XA_ONE_PHASE)
{
int r;
@@ -4601,7 +4636,7 @@ end_with_restore_list:
else
send_ok(thd);
}
- else if (thd->transaction.xa_state == XA_PREPARED &&
+ else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
thd->lex->xa_opt == XA_NONE)
{
if (wait_if_global_read_lock(thd, 0, 0))
@@ -4621,27 +4656,33 @@ end_with_restore_list:
else
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
case SQLCOM_XA_ROLLBACK:
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
- if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0)))
+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
+ if (!xs || xs->in_thd)
my_error(ER_XAER_NOTA, MYF(0));
else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ xid_cache_delete(xs);
send_ok(thd);
+ }
break;
}
- if (thd->transaction.xa_state != XA_IDLE &&
- thd->transaction.xa_state != XA_PREPARED)
+ if (thd->transaction.xid_state.xa_state != XA_IDLE &&
+ thd->transaction.xid_state.xa_state != XA_PREPARED)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
if (ha_rollback(thd))
@@ -4650,7 +4691,8 @@ end_with_restore_list:
send_ok(thd);
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
@@ -5167,17 +5209,21 @@ void mysql_reset_thd_for_next_command(THD *thd)
DBUG_ENTER("mysql_reset_thd_for_next_command");
thd->free_list= 0;
thd->select_number= 1;
- thd->total_warn_count=0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
- thd->sent_row_count= thd->examined_row_count= 0;
- thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
+ thd->is_fatal_error= thd->time_zone_used= 0;
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
thd->tmp_table_used= 0;
- if (opt_bin_log)
- reset_dynamic(&thd->user_var_events);
- thd->clear_error();
+ if (!thd->in_sub_stmt)
+ {
+ if (opt_bin_log)
+ reset_dynamic(&thd->user_var_events);
+ thd->clear_error();
+ thd->total_warn_count=0; // Warnings for this query
+ thd->rand_used= 0;
+ thd->sent_row_count= thd->examined_row_count= 0;
+ }
DBUG_VOID_RETURN;
}
@@ -5206,9 +5252,9 @@ mysql_new_select(LEX *lex, bool move_down)
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
select_lex->select_number= ++thd->select_number;
+ select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
- select_lex->parent_lex= lex;
/*
Don't evaluate this subquery during statement prepare even if
it's a constant one. The flag is switched off in the end of
@@ -5266,6 +5312,7 @@ mysql_new_select(LEX *lex, bool move_down)
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
+ fake->parent_lex= lex; /* Used in init_query. */
fake->make_empty_select();
fake->linkage= GLOBAL_OPTIONS_TYPE;
fake->select_limit= 0;
@@ -5274,6 +5321,11 @@ mysql_new_select(LEX *lex, bool move_down)
/* allow item list resolving in fake select for ORDER BY */
fake->context.resolve_in_select_list= TRUE;
fake->context.select_lex= fake;
+ /*
+ Remove the name resolution context of the fake select from the
+ context stack.
+ */
+ lex->pop_context();
}
select_lex->context.outer_context= outer_context;
}
@@ -5322,10 +5374,12 @@ void create_select_for_variable(const char *var_name)
We set the name of Item to @@session.var_name because that then is used
as the column name in the output.
*/
- var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string);
- end= strxmov(buff, "@@session.", var_name, NullS);
- var->set_name(buff, end-buff, system_charset_info);
- add_item_to_list(thd, var);
+ if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
+ {
+ end= strxmov(buff, "@@session.", var_name, NullS);
+ var->set_name(buff, end-buff, system_charset_info);
+ add_item_to_list(thd, var);
+ }
DBUG_VOID_RETURN;
}
@@ -5351,11 +5405,12 @@ void mysql_init_multi_delete(LEX *lex)
void mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
-
mysql_init_query(thd, (uchar*) inBuf, length);
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex= thd->lex;
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
if (!yyparse((void *)thd) && ! thd->is_fatal_error)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -5823,7 +5878,7 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
new_field->length= 1;
if (new_field->length > MAX_BIT_FIELD_LENGTH)
{
- my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
MAX_BIT_FIELD_LENGTH);
DBUG_RETURN(NULL);
}
@@ -5842,7 +5897,10 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
type != MYSQL_TYPE_STRING &&
type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
{
- my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
+ my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR ||
+ type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
+ ER_TOO_BIG_DISPLAYWIDTH,
+ MYF(0),
field_name, max_field_charlength); /* purecov: inspected */
DBUG_RETURN(NULL);
}
@@ -5961,9 +6019,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
+ TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
char *alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
+ LINT_INIT(previous_table_ref);
if (!table)
DBUG_RETURN(0); // End of memory
@@ -6056,8 +6116,34 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
}
- /* Link table in local list (list for current select) */
+ /* Store the table reference preceding the current one. */
+ if (table_list.elements > 0)
+ {
+ /*
+ table_list.next points to the last inserted TABLE_LIST->next_local'
+ element
+ */
+ previous_table_ref= (TABLE_LIST*) (table_list.next -
+ offsetof(TABLE_LIST, next_local));
+ DBUG_ASSERT(previous_table_ref);
+ /*
+ Set next_name_resolution_table of the previous table reference to point
+ to the current table reference. In effect the list
+ TABLE_LIST::next_name_resolution_table coincides with
+ TABLE_LIST::next_local. Later this may be changed in
+ store_top_level_join_columns() for NATURAL/USING joins.
+ */
+ previous_table_ref->next_name_resolution_table= ptr;
+ }
+
+ /*
+ Link the current table reference in a local list (list for current select).
+ Notice that as a side effect here we set the next_local field of the
+ previous table reference to 'ptr'. Here we also add one element to the
+ list 'table_list'.
+ */
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
+ ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
DBUG_RETURN(ptr);
@@ -6091,10 +6177,12 @@ bool st_select_lex::init_nested_join(THD *thd)
NESTED_JOIN *nested_join;
DBUG_ENTER("init_nested_join");
- if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
- !(nested_join= ptr->nested_join=
- (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
+ sizeof(NESTED_JOIN))))
DBUG_RETURN(1);
+ nested_join= ptr->nested_join=
+ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+
join_list->push_front(ptr);
ptr->embedding= embedding;
ptr->join_list= join_list;
@@ -6162,30 +6250,48 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
The function nest last join operation as if it was enclosed in braces.
RETURN VALUE
- Pointer to TABLE_LIST element created for the new nested join, if success
- 0, otherwise
+ 0 Error
+ # Pointer to TABLE_LIST element created for the new nested join
+
*/
TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
TABLE_LIST *ptr;
NESTED_JOIN *nested_join;
+ List<TABLE_LIST> *embedded_list;
DBUG_ENTER("nest_last_join");
- if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
- !(nested_join= ptr->nested_join=
- (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
+ sizeof(NESTED_JOIN))))
DBUG_RETURN(0);
+ nested_join= ptr->nested_join=
+ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+
ptr->embedding= embedding;
ptr->join_list= join_list;
- List<TABLE_LIST> *embedded_list= &nested_join->join_list;
+ embedded_list= &nested_join->join_list;
embedded_list->empty();
- for (int i=0; i < 2; i++)
+
+ for (uint i=0; i < 2; i++)
{
TABLE_LIST *table= join_list->pop();
table->join_list= embedded_list;
table->embedding= ptr;
embedded_list->push_back(table);
+ if (table->natural_join)
+ {
+ ptr->is_natural_join= TRUE;
+ /*
+ If this is a JOIN ... USING, move the list of joined fields to the
+ table reference that describes the join.
+ */
+ if (table->join_using_fields)
+ {
+ ptr->join_using_fields= table->join_using_fields;
+ table->join_using_fields= NULL;
+ }
+ }
}
join_list->push_front(ptr);
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
@@ -6194,44 +6300,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
/*
- Save names for a join with using clause
-
- SYNOPSIS
- save_names_for_using_list
- tab1 left table in join
- tab2 right table in join
-
- DESCRIPTION
- The function saves the full names of the tables in st_select_lex
- to be able to build later an on expression to replace the using clause.
-
- RETURN VALUE
- None
-*/
-
-void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
- TABLE_LIST *tab2)
-{
- while (tab1->nested_join)
- {
- tab1= tab1->nested_join->join_list.head();
- }
- db1= tab1->db;
- table1= tab1->alias;
- while (tab2->nested_join)
- {
- TABLE_LIST *next;
- List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
- tab2= it++;
- while ((next= it++))
- tab2= next;
- }
- db2= tab2->db;
- table2= tab2->alias;
-}
-
-
-/*
Add a table to the current join list
SYNOPSIS
@@ -6334,16 +6402,70 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
}
-void add_join_on(TABLE_LIST *b,Item *expr)
+/*
+ Create a new name resolution context for a JOIN ... ON clause.
+
+ SYNOPSIS
+ make_join_on_context()
+ thd pointer to current thread
+ left_op lefto operand of the JOIN
+ right_op rigth operand of the JOIN
+
+ DESCRIPTION
+ Create a new name resolution context for a JOIN ... ON clause,
+ and set the first and last leaves of the list of table references
+ to be used for name resolution.
+
+ RETURN
+ A new context if all is OK
+ NULL - if a memory allocation error occured
+*/
+
+Name_resolution_context *
+make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op)
+{
+ Name_resolution_context *on_context;
+ if (!(on_context= new (thd->mem_root) Name_resolution_context))
+ return NULL;
+ on_context->init();
+ on_context->first_name_resolution_table=
+ left_op->first_leaf_for_name_resolution();
+ on_context->last_name_resolution_table=
+ right_op->last_leaf_for_name_resolution();
+ return on_context;
+}
+
+
+/*
+ Add an ON condition to the second operand of a JOIN ... ON.
+
+ SYNOPSIS
+ add_join_on
+ b the second operand of a JOIN ... ON
+ expr the condition to be added to the ON clause
+
+ DESCRIPTION
+ Add an ON condition to the right operand of a JOIN ... ON clause.
+
+ RETURN
+ FALSE if there was some error
+ TRUE if all is OK
+*/
+
+void add_join_on(TABLE_LIST *b, Item *expr)
{
if (expr)
{
if (!b->on_expr)
- b->on_expr=expr;
+ b->on_expr= expr;
else
{
- /* This only happens if you have both a right and left join */
- b->on_expr=new Item_cond_and(b->on_expr,expr);
+ /*
+ If called from the parser, this happens if you have both a
+ right and left join. If called later, it happens if we add more
+ than one condition to the ON clause.
+ */
+ b->on_expr= new Item_cond_and(b->on_expr,expr);
}
b->on_expr->top_level_item();
}
@@ -6351,46 +6473,67 @@ void add_join_on(TABLE_LIST *b,Item *expr)
/*
- Mark that we have a NATURAL JOIN between two tables
+ Mark that there is a NATURAL JOIN or JOIN ... USING between two
+ tables.
SYNOPSIS
add_join_natural()
- a Table to do normal join with
- b Do normal join with this table
-
+ a Left join argument
+ b Right join argument
+ using_fields Field names from USING clause
+
IMPLEMENTATION
- This function just marks that table b should be joined with a.
- The function setup_cond() will create in b->on_expr a list
- of equal condition between all fields of the same name.
-
+ This function marks that table b should be joined with a either via
+ a NATURAL JOIN or via JOIN ... USING. Both join types are special
+ cases of each other, so we treat them together. The function
+ setup_conds() creates a list of equal condition between all fields
+ of the same name for NATURAL JOIN or the fields in 'using_fields'
+ for JOIN ... USING. The list of equality conditions is stored
+ either in b->on_expr, or in JOIN::conds, depending on whether there
+ was an outer join.
+
+ EXAMPLE
SELECT * FROM t1 NATURAL LEFT JOIN t2
<=>
SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
+
+ SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond>
+ <=>
+ SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>)
+
+ SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
+ <=>
+ SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)
+
+ RETURN
+ None
*/
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
+void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
{
- b->natural_join=a;
+ b->natural_join= a;
+ b->join_using_fields= using_fields;
}
+
/*
Reload/resets privileges and the different caches.
SYNOPSIS
reload_acl_and_cache()
- thd Thread handler
+ thd Thread handler (can be NULL!)
options What should be reset/reloaded (tables, privileges,
slave...)
tables Tables to flush (if any)
write_to_binlog Depending on 'options', it may be very bad to write the
query to the binlog (e.g. FLUSH SLAVE); this is a
- pointer where, if it is not NULL, reload_acl_and_cache()
- will put 0 if it thinks we really should not write to
- the binlog. Otherwise it will put 1.
+ pointer where reload_acl_and_cache() will put 0 if
+ it thinks we really should not write to the binlog.
+ Otherwise it will put 1.
RETURN
0 ok
- !=0 error
+ !=0 error. thd->killed or thd->net.report_error is set
*/
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
@@ -6399,6 +6542,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool result=0;
select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1;
+
+ if (thd && thd->in_sub_stmt)
+ {
+ my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
+ return 1;
+ }
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_GRANT)
{
@@ -6454,15 +6604,34 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if ((options & REFRESH_READ_LOCK) && thd)
{
/*
+ We must not try to aspire a global read lock if we have a write
+ locked table. This would lead to a deadlock when trying to
+ reopen (and re-lock) the table after the flush.
+ */
+ if (thd->locked_tables)
+ {
+ THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
+ THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;
+
+ for (; lock_p < end_p; lock_p++)
+ {
+ if ((*lock_p)->type == TL_WRITE)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ return 1;
+ }
+ }
+ }
+ /*
Writing to the binlog could cause deadlocks, as we don't log
UNLOCK TABLES
*/
tmp_write_to_binlog= 0;
if (lock_global_read_lock(thd))
- return 1;
+ return 1; // Killed
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
tables);
- if (make_global_read_lock_block_commit(thd))
+ if (make_global_read_lock_block_commit(thd)) // Killed
{
/* Don't leave things in a half-locked state */
unlock_global_read_lock(thd);
@@ -6484,7 +6653,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
{
tmp_write_to_binlog= 0;
if (reset_master(thd))
+ {
result=1;
+ thd->fatal_error(); // Ensure client get error
+ }
}
#endif
#ifdef OPENSSL
@@ -6506,8 +6678,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
#endif
if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL);
- if (write_to_binlog)
- *write_to_binlog= tmp_write_to_binlog;
+ *write_to_binlog= tmp_write_to_binlog;
return result;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index a601e7c68b7..082ae783ca8 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -73,6 +73,7 @@ Long data handling:
#include <m_ctype.h> // for isspace()
#include "sp_head.h"
#include "sp.h"
+#include "sp_cache.h"
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
@@ -88,6 +89,7 @@ class Prepared_statement: public Statement
{
public:
THD *thd;
+ Protocol *protocol;
Item_param **param_array;
uint param_count;
uint last_errno;
@@ -549,7 +551,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
param->set_param_func= set_param_str;
- param->value.cs_info.character_set_client= &my_charset_bin;
+ param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
+ param->value.cs_info.character_set_client=
+ 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;
@@ -565,6 +569,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
+ param->value.cs_info.character_set_of_placeholder= fromcs;
param->value.cs_info.character_set_client= fromcs;
/*
@@ -927,7 +932,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
If we would use locks, then we have to ensure we are not using
TL_WRITE_DELAYED as having two such locks can cause table corruption.
*/
- if (open_normal_and_derived_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list, 0))
goto error;
if ((values= its++))
@@ -1007,7 +1012,7 @@ static int mysql_test_update(Prepared_statement *stmt,
if (update_precheck(thd, table_list))
goto error;
- if (open_tables(thd, &table_list, &table_count))
+ if (open_tables(thd, &table_list, &table_count, 0))
goto error;
if (table_list->multitable_view)
@@ -1781,6 +1786,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
mysql_reset_errors(thd, 0);
lex= thd->lex;
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
+
error= yyparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(stmt);
lex->safe_to_cache_query= 0;
@@ -1850,6 +1858,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
SELECT_LEX *sl= lex->all_selects_list;
DBUG_ENTER("reinit_stmt_before_use");
+ /*
+ We have to update "thd" pointer in LEX, all its units and in LEX::result,
+ since statements which belong to trigger body are associated with TABLE
+ object and because of this can be used in different threads.
+ */
+ lex->thd= thd;
+
if (lex->empty_field_list_on_rset)
{
lex->empty_field_list_on_rset= 0;
@@ -1888,6 +1903,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
unit->types.empty();
/* for derived tables & PS (which can't be reset by Item_subquery) */
unit->reinit_exec_mechanism();
+ unit->set_thd(thd);
}
}
@@ -1926,7 +1942,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
lex->select_lex.leaf_tables= lex->leaf_tables_insert;
if (lex->result)
+ {
lex->result->cleanup();
+ lex->result->set_thd(thd);
+ }
DBUG_VOID_RETURN;
}
@@ -2021,6 +2040,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN;
/* If lex->result is set, mysql_execute_command will use it */
stmt->lex->result= &cursor->result;
+ stmt->protocol= &cursor->protocol;
thd->lock_id= &cursor->lock_id;
}
}
@@ -2055,9 +2075,11 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
}
mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query);
- thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ thd->protocol= stmt->protocol; // Switch to binary protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
+ sp_cache_flush_obsolete(&thd->sp_func_cache);
mysql_execute_command(thd);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
@@ -2247,7 +2269,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
- thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ thd->protocol= stmt->protocol; // Switch to binary protocol
cursor->fetch(num_rows);
thd->protocol= &thd->protocol_simple; // Use normal protocol
@@ -2419,6 +2441,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
thd_arg->variables.query_alloc_block_size,
thd_arg->variables.query_prealloc_size),
thd(thd_arg),
+ protocol(&thd_arg->protocol_prep),
param_array(0),
param_count(0),
last_errno(0)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 21277dfc1af..593f294ae0e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -338,7 +338,7 @@ 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,
+ setup_tables(thd, &select_lex->context, join_list,
tables_list, &conds, &select_lex->leaf_tables,
FALSE)) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
@@ -1086,9 +1086,10 @@ JOIN::optimize()
order=0;
}
}
-
- if (thd->lex->subqueries)
+
+ if (select_lex->uncacheable && !is_top_level_join())
{
+ /* If this join belongs to an uncacheable subquery */
if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
DBUG_RETURN(-1);
error= 0; // Ensure that tmp_join.error= 0
@@ -1282,7 +1283,15 @@ JOIN::exec()
if (need_tmp)
{
if (tmp_join)
+ {
+ /*
+ We are in a non cacheable sub query. Get the saved join structure
+ after optimization.
+ (curr_join may have been modified during last exection and we need
+ to reset it)
+ */
curr_join= tmp_join;
+ }
curr_tmp_table= exec_tmp_table1;
/* Copy data to the temporary table */
@@ -1576,7 +1585,8 @@ JOIN::exec()
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
~ (table_map) 0,
~used_tables);
- DBUG_EXECUTE("where",print_where(conds,"having after sort"););
+ DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
+ "having after sort"););
}
}
{
@@ -1647,9 +1657,7 @@ JOIN::exec()
curr_join->fields= curr_fields_list;
curr_join->procedure= procedure;
- if (unit == &thd->lex->unit &&
- (unit->fake_select_lex == 0 || select_lex == unit->fake_select_lex) &&
- thd->cursor && tables != const_tables)
+ if (is_top_level_join() && thd->cursor && tables != const_tables)
{
/*
We are here if this is JOIN::exec for the last select of the main unit
@@ -1726,6 +1734,7 @@ JOIN::destroy()
Cursor::Cursor(THD *thd)
:Query_arena(&main_mem_root, INITIALIZED),
join(0), unit(0),
+ protocol(thd),
close_at_commit(FALSE)
{
/* We will overwrite it at open anyway. */
@@ -8142,7 +8151,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- ulong select_options, ha_rows rows_limit,
+ ulonglong select_options, ha_rows rows_limit,
char *table_alias)
{
TABLE *table;
@@ -8400,7 +8409,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
/* If result table is small; use a heap */
if (blob_count || using_unique_constraint ||
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
- OPTION_BIG_TABLES)
+ OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM))
{
table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM);
if (group &&
@@ -11934,13 +11943,14 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
SYNOPSIS
find_order_in_list()
- thd Pointer to current thread structure
- ref_pointer_array All select, group and order by fields
- tables List of tables to search in (usually FROM clause)
- order Column reference to be resolved
- fields List of fields to search in (usually SELECT list)
- all_fields All select, group and order by fields
- is_group_field True if order is a GROUP field, false if ORDER by field
+ thd [in] Pointer to current thread structure
+ ref_pointer_array [in/out] All select, group and order by fields
+ tables [in] List of tables to search in (usually FROM clause)
+ order [in] Column reference to be resolved
+ fields [in] List of fields to search in (usually SELECT list)
+ all_fields [in/out] All select, group and order by fields
+ is_group_field [in] True if order is a GROUP field, false if
+ ORDER by field
DESCRIPTION
Given a column reference (represented by 'order') from a GROUP BY or ORDER
@@ -12016,7 +12026,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
order_item_type == Item::REF_ITEM)
{
from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
- &view_ref, IGNORE_ERRORS, TRUE,
+ NULL, &view_ref, IGNORE_ERRORS, TRUE,
FALSE);
if (!from_field)
from_field= (Field*) not_found_field;
@@ -12250,9 +12260,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array,
li.rewind();
while ((item=li++))
{
- if (item->const_item() || item->with_sum_func)
- continue;
- if (!item->marker)
+ if (!item->const_item() && !item->with_sum_func && !item->marker)
{
ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 7fdd26846a6..77a3f872064 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -203,7 +203,7 @@ class JOIN :public Sql_alloc
Item *having;
Item *tmp_having; // To store having when processed temporary table
Item *having_history; // Store having for explain
- uint select_options;
+ ulonglong select_options;
select_result *result;
TMP_TABLE_PARAM tmp_table_param;
MYSQL_LOCK *lock;
@@ -259,14 +259,14 @@ class JOIN :public Sql_alloc
bool union_part; // this subselect is part of union
bool optimized; // flag to avoid double optimization in EXPLAIN
- JOIN(THD *thd_arg, List<Item> &fields_arg, ulong select_options_arg,
+ JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
:fields_list(fields_arg)
{
init(thd_arg, fields_arg, select_options_arg, result_arg);
}
- void init(THD *thd_arg, List<Item> &fields_arg, ulong select_options_arg,
+ void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
{
join_tab= join_tab_save= 0;
@@ -367,6 +367,11 @@ class JOIN :public Sql_alloc
!group_list);
}
bool change_result(select_result *result);
+ bool is_top_level_join() const
+ {
+ return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
+ select_lex == unit->fake_select_lex));
+ }
};
@@ -397,6 +402,7 @@ class Cursor: public Sql_alloc, public Query_arena
};
Engine_info ht_info[MAX_HA];
public:
+ Protocol_prep protocol;
Item_change_list change_list;
select_send result;
THR_LOCK_OWNER lock_id;
@@ -432,7 +438,7 @@ void TEST_join(JOIN *join);
bool store_val_in_field(Field *field,Item *val);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- ulong select_options, ha_rows rows_limit,
+ ulonglong select_options, ha_rows rows_limit,
char* alias);
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
void free_tmp_table(THD *thd, TABLE *entry);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index e0c40b3466e..feeed2716fc 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -20,6 +20,7 @@
#include "mysql_priv.h"
#include "sql_select.h" // For select_describe
#include "repl_failsafe.h"
+#include "sp.h"
#include "sp_head.h"
#include "sql_trigger.h"
#include <my_dir.h>
@@ -263,8 +264,14 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
bzero((char*) &table_list,sizeof(table_list));
- if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0)))))
+ if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
+ {
+ if (my_errno == ENOENT)
+ my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
+ else
+ my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
DBUG_RETURN(-1);
+ }
for (i=0 ; i < (uint) dirp->number_off_files ; i++)
{
@@ -352,7 +359,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
thd->lex->view_prepare_mode= TRUE;
/* Only one table for now, but VIEW can involve several tables */
- if (open_normal_and_derived_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list, 0))
{
DBUG_RETURN(TRUE);
}
@@ -551,7 +558,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
DBUG_ENTER("mysqld_list_fields");
DBUG_PRINT("enter",("table: %s",table_list->table_name));
- if (open_normal_and_derived_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list, 0))
DBUG_VOID_RETURN;
table= table_list->table;
@@ -619,7 +626,7 @@ static const char *require_quotes(const char *name, uint name_length)
uint length;
const char *end= name + name_length;
- for ( ; name < end ; name++)
+ for (; name < end ; name++)
{
uchar chr= (uchar) *name;
length= my_mbcharlen(system_charset_info, chr);
@@ -1720,7 +1727,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_TRIGGERS:
- index_field_values->db_value= lex->current_select->db;
+ index_field_values->db_value= lex->select_lex.db;
index_field_values->table_value= wild;
break;
default:
@@ -1929,7 +1936,7 @@ int make_db_list(THD *thd, List<char> *files,
int schema_tables_add(THD *thd, List<char> *files, const char *wild)
{
ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
- for ( ; tmp_schema_table->table_name; tmp_schema_table++)
+ for (; tmp_schema_table->table_name; tmp_schema_table++)
{
if (tmp_schema_table->hidden)
continue;
@@ -1958,6 +1965,8 @@ 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;
SELECT_LEX sel;
@@ -1966,40 +1975,51 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
uint len;
bool with_i_schema;
enum enum_schema_tables schema_table_idx;
- thr_lock_type lock_type;
List<char> bases;
List_iterator_fast<char> it(bases);
COND *partial_cond;
uint derived_tables= lex->derived_tables;
int error= 1;
+ Open_tables_state open_tables_state_backup;
DBUG_ENTER("get_all_tables");
LINT_INIT(end);
LINT_INIT(len);
+ /*
+ Let us set fake sql_command so views won't try to merge
+ themselves into main statement.
+ */
+ lex->sql_command= SQLCOM_SHOW_FIELDS;
+
+ /*
+ We should not introduce deadlocks even if we already have some
+ tables open and locked, since we won't lock tables which we will
+ open and will ignore possible name-locks for these tables.
+ */
+ thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
+
if (lsel)
{
- TABLE *old_open_tables= thd->open_tables;
TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
bool res;
lex->all_selects_list= lsel;
- res= open_normal_and_derived_tables(thd, show_table_list);
- if (schema_table->process_table(thd, show_table_list,
+ res= open_normal_and_derived_tables(thd, show_table_list,
+ MYSQL_LOCK_IGNORE_FLUSH);
+ /*
+ get_all_tables() returns 1 on failure and 0 on success thus
+ return only these and not the result code of ::process_table()
+ */
+ error= test(schema_table->process_table(thd, show_table_list,
table, res, show_table_list->db,
- show_table_list->alias))
- goto err;
- close_thread_tables(thd, 0, 0, old_open_tables);
+ show_table_list->alias));
+ close_thread_tables(thd);
show_table_list->table= 0;
- error= 0;
goto err;
}
schema_table_idx= get_schema_table_idx(schema_table);
- lock_type= TL_UNLOCK;
-
- if (schema_table_idx == SCH_TABLES)
- lock_type= TL_READ;
if (make_db_list(thd, &bases, &idx_field_vals,
&with_i_schema, 0))
@@ -2056,7 +2076,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
if (with_i_schema)
{
- table->field[3]->store("TEMPORARY", 9, system_charset_info);
+ table->field[3]->store("SYSTEM VIEW", 11, system_charset_info);
}
else
{
@@ -2082,19 +2102,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
int res;
- TABLE *old_open_tables= thd->open_tables;
+ /*
+ 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))
goto err;
TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
- show_table_list->lock_type= lock_type;
lex->all_selects_list= &sel;
lex->derived_tables= 0;
- res= open_normal_and_derived_tables(thd, show_table_list);
- if (schema_table->process_table(thd, show_table_list, table,
+ res= open_normal_and_derived_tables(thd, show_table_list,
+ MYSQL_LOCK_IGNORE_FLUSH);
+ res= schema_table->process_table(thd, show_table_list, table,
res, base_name,
- show_table_list->alias))
+ show_table_list->alias);
+ close_thread_tables(thd);
+ if (res)
goto err;
- close_thread_tables(thd, 0, 0, old_open_tables);
}
}
}
@@ -2108,8 +2133,12 @@ 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->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
+ lex->query_tables_last= save_query_tables_last;
+ *save_query_tables_last= 0;
+ lex->sql_command= save_sql_command;
DBUG_RETURN(error);
}
@@ -2206,7 +2235,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
else if (tables->view)
{
table->field[3]->store("VIEW", 4, cs);
- table->field[20]->store("view", 4, cs);
+ table->field[20]->store("VIEW", 4, cs);
}
else
{
@@ -2214,8 +2243,11 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
TABLE_SHARE *share= show_table->s;
handler *file= show_table->file;
- file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
- if (share->tmp_table == TMP_TABLE)
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO |
+ HA_STATUS_NO_LOCK);
+ if (share->tmp_table == SYSTEM_TMP_TABLE)
+ table->field[3]->store("SYSTEM VIEW", 11, cs);
+ else if (share->tmp_table)
table->field[3]->store("TEMPORARY", 9, cs);
else
table->field[3]->store("BASE TABLE", 10, cs);
@@ -2270,13 +2302,8 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
table->field[12]->store((longlong) file->delete_length);
if (show_table->found_next_number_field)
{
- show_table->next_number_field=show_table->found_next_number_field;
- show_table->next_number_field->reset();
- file->update_auto_increment();
- table->field[13]->store((longlong) show_table->
- next_number_field->val_int());
+ table->field[13]->store((longlong) file->auto_increment_value);
table->field[13]->set_notnull();
- show_table->next_number_field=0;
}
if (file->create_time)
{
@@ -2371,7 +2398,13 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
LEX *lex= thd->lex;
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
CHARSET_INFO *cs= system_charset_info;
+ TABLE *show_table;
+ handler *file;
+ Field **ptr,*field;
+ int count;
+ uint base_name_length, file_name_length;
DBUG_ENTER("get_schema_column_record");
+
if (res)
{
if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS)
@@ -2388,186 +2421,187 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
DBUG_RETURN(res);
}
- TABLE *show_table= tables->table;
- handler *file= show_table->file;
+ show_table= tables->table;
+ file= show_table->file;
+ count= 0;
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
restore_record(show_table, s->default_values);
- Field **ptr,*field;
- int count= 0;
+ base_name_length= strlen(base_name);
+ file_name_length= strlen(file_name);
+
for (ptr=show_table->field; (field= *ptr) ; ptr++)
{
- if (!wild || !wild[0] ||
- !wild_case_compare(system_charset_info, field->field_name,wild))
- {
- const char *tmp_buff;
- byte *pos;
- bool is_blob;
- uint flags=field->flags;
- char tmp[MAX_FIELD_WIDTH];
- char tmp1[MAX_FIELD_WIDTH];
- String type(tmp,sizeof(tmp), system_charset_info);
- char *end= tmp;
- count++;
- restore_record(table, s->default_values);
+ const char *tmp_buff;
+ byte *pos;
+ bool is_blob;
+ uint flags=field->flags;
+ char tmp[MAX_FIELD_WIDTH];
+ char tmp1[MAX_FIELD_WIDTH];
+ String type(tmp,sizeof(tmp), system_charset_info);
+ char *end;
+ int decimals, field_length;
+
+ if (wild && wild[0] &&
+ wild_case_compare(system_charset_info, field->field_name,wild))
+ continue;
+
+ flags= field->flags;
+ count++;
+ /* Get default row, with all NULL fields set to NULL */
+ restore_record(table, s->default_values);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint col_access;
- check_access(thd,SELECT_ACL | EXTRA_ACL, base_name,
- &tables->grant.privilege, 0, 0);
- col_access= get_column_grant(thd, &tables->grant,
- base_name, file_name,
- field->field_name) & COL_ACLS;
- if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS &&
- !tables->schema_table && !col_access)
- continue;
- for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
+ uint col_access;
+ check_access(thd,SELECT_ACL | EXTRA_ACL, base_name,
+ &tables->grant.privilege, 0, 0);
+ col_access= get_column_grant(thd, &tables->grant,
+ base_name, file_name,
+ field->field_name) & COL_ACLS;
+ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS &&
+ !tables->schema_table && !col_access)
+ continue;
+ end= tmp;
+ for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
+ {
+ if (col_access & 1)
{
- if (col_access & 1)
- {
- *end++=',';
- end=strmov(end,grant_types.type_names[bitnr]);
- }
+ *end++=',';
+ end=strmov(end,grant_types.type_names[bitnr]);
}
- if (tables->schema_table) // any user has 'select' privilege on all
- // I_S table columns
- table->field[17]->store(grant_types.type_names[0],
- strlen(grant_types.type_names[0]), cs);
- else
- table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
+ }
+ if (tables->schema_table) // any user has 'select' privilege on all
+ // I_S table columns
+ table->field[17]->store(grant_types.type_names[0],
+ strlen(grant_types.type_names[0]), cs);
+ else
+ table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
-#else
- *end= 0;
#endif
- table->field[1]->store(base_name, strlen(base_name), cs);
- table->field[2]->store(file_name, strlen(file_name), cs);
- table->field[3]->store(field->field_name, strlen(field->field_name),
- cs);
- table->field[4]->store((longlong) count);
- field->sql_type(type);
- table->field[14]->store(type.ptr(), type.length(), cs);
- tmp_buff= strchr(type.ptr(), '(');
- table->field[7]->store(type.ptr(),
- (tmp_buff ? tmp_buff - type.ptr() :
- type.length()), cs);
- if (show_table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD)
- {
- table->field[5]->store("CURRENT_TIMESTAMP", 17, cs);
- table->field[5]->set_notnull();
- }
- else if (field->unireg_check != Field::NEXT_NUMBER &&
- !field->is_null() &&
- !(field->flags & NO_DEFAULT_VALUE_FLAG))
- {
- String def(tmp1,sizeof(tmp1), cs);
- type.set(tmp, sizeof(tmp), field->charset());
- field->val_str(&type);
- uint dummy_errors;
- def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
- table->field[5]->store(def.ptr(), def.length(), def.charset());
- table->field[5]->set_notnull();
- }
- else if (field->unireg_check == Field::NEXT_NUMBER ||
- field->maybe_null())
- table->field[5]->set_null(); // Null as default
- else
- {
- table->field[5]->store("",0, cs);
- table->field[5]->set_notnull();
- }
- pos=(byte*) ((flags & NOT_NULL_FLAG) &&
- field->type() != FIELD_TYPE_TIMESTAMP ?
- "NO" : "YES");
- table->field[6]->store((const char*) pos,
- strlen((const char*) pos), cs);
- is_blob= (field->type() == FIELD_TYPE_BLOB);
- if (field->has_charset() || is_blob)
- {
- longlong c_octet_len= is_blob ? (longlong) field->max_length() :
- (longlong) field->max_length()/field->charset()->mbmaxlen;
- table->field[8]->store(c_octet_len);
- table->field[8]->set_notnull();
- table->field[9]->store((longlong) field->max_length());
- table->field[9]->set_notnull();
- }
+ table->field[1]->store(base_name, base_name_length, cs);
+ table->field[2]->store(file_name, file_name_length, cs);
+ table->field[3]->store(field->field_name, strlen(field->field_name),
+ cs);
+ table->field[4]->store((longlong) count);
+ field->sql_type(type);
+ table->field[14]->store(type.ptr(), type.length(), cs);
+ tmp_buff= strchr(type.ptr(), '(');
+ table->field[7]->store(type.ptr(),
+ (tmp_buff ? tmp_buff - type.ptr() :
+ type.length()), cs);
+ if (show_table->timestamp_field == field &&
+ field->unireg_check != Field::TIMESTAMP_UN_FIELD)
+ {
+ table->field[5]->store("CURRENT_TIMESTAMP", 17, cs);
+ table->field[5]->set_notnull();
+ }
+ else if (field->unireg_check != Field::NEXT_NUMBER &&
+ !field->is_null() &&
+ !(field->flags & NO_DEFAULT_VALUE_FLAG))
+ {
+ String def(tmp1,sizeof(tmp1), cs);
+ type.set(tmp, sizeof(tmp), field->charset());
+ field->val_str(&type);
+ uint dummy_errors;
+ def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
+ table->field[5]->store(def.ptr(), def.length(), def.charset());
+ table->field[5]->set_notnull();
+ }
+ else if (field->unireg_check == Field::NEXT_NUMBER ||
+ lex->orig_sql_command != SQLCOM_SHOW_FIELDS ||
+ field->maybe_null())
+ table->field[5]->set_null(); // Null as default
+ else
+ {
+ table->field[5]->store("",0, cs);
+ table->field[5]->set_notnull();
+ }
+ pos=(byte*) ((flags & NOT_NULL_FLAG) &&
+ field->type() != FIELD_TYPE_TIMESTAMP ?
+ "NO" : "YES");
+ table->field[6]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ is_blob= (field->type() == FIELD_TYPE_BLOB);
+ if (field->has_charset() || is_blob)
+ {
+ longlong c_octet_len= is_blob ? (longlong) field->max_length() :
+ (longlong) field->max_length()/field->charset()->mbmaxlen;
+ table->field[8]->store(c_octet_len);
+ table->field[8]->set_notnull();
+ table->field[9]->store((longlong) field->max_length());
+ table->field[9]->set_notnull();
+ }
- {
- uint dec =field->decimals();
- switch (field->type()) {
- case FIELD_TYPE_NEWDECIMAL:
- table->field[10]->store((longlong)
- ((Field_new_decimal*)field)->precision);
- table->field[10]->set_notnull();
- table->field[11]->store((longlong) field->decimals());
- table->field[11]->set_notnull();
- break;
- case FIELD_TYPE_DECIMAL:
- {
- uint int_part=field->field_length - (dec ? dec + 1 : 0);
- table->field[10]->store((longlong) (int_part + dec - 1));
- table->field[10]->set_notnull();
- table->field[11]->store((longlong) field->decimals());
- table->field[11]->set_notnull();
- break;
- }
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- {
- table->field[10]->store((longlong) field->max_length() - 1);
- table->field[10]->set_notnull();
- break;
- }
- case FIELD_TYPE_BIT:
- {
- table->field[10]->store((longlong) field->max_length());
- table->field[10]->set_notnull();
- break;
- }
- case FIELD_TYPE_FLOAT:
- case FIELD_TYPE_DOUBLE:
- {
- table->field[10]->store((longlong) field->field_length);
- table->field[10]->set_notnull();
- if (dec != NOT_FIXED_DEC)
- {
- table->field[11]->store((longlong) dec);
- table->field[11]->set_notnull();
- }
- break;
- }
- default:
- break;
- }
- }
- if (field->has_charset())
- {
- pos=(byte*) field->charset()->csname;
- table->field[12]->store((const char*) pos,
- strlen((const char*) pos), cs);
- table->field[12]->set_notnull();
- pos=(byte*) field->charset()->name;
- table->field[13]->store((const char*) pos,
- strlen((const char*) pos), cs);
- table->field[13]->set_notnull();
- }
- pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
- (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
- (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- table->field[15]->store((const char*) pos,
- strlen((const char*) pos), cs);
- end= tmp;
- if (field->unireg_check == Field::NEXT_NUMBER)
- end=strmov(tmp,"auto_increment");
- table->field[16]->store(tmp, (uint) (end-tmp), cs);
+ /*
+ Calculate field_length and decimals.
+ They are set to -1 if they should not be set (we should return NULL)
+ */
- end=tmp;
- table->field[18]->store(field->comment.str, field->comment.length, cs);
- if (schema_table_store_record(thd, table))
- DBUG_RETURN(1);
+ decimals= field->decimals();
+ switch (field->type()) {
+ case FIELD_TYPE_NEWDECIMAL:
+ field_length= ((Field_new_decimal*) field)->precision;
+ break;
+ case FIELD_TYPE_DECIMAL:
+ field_length= field->field_length - (decimals ? 2 : 1);
+ break;
+ case FIELD_TYPE_TINY:
+ case FIELD_TYPE_SHORT:
+ case FIELD_TYPE_LONG:
+ case FIELD_TYPE_LONGLONG:
+ case FIELD_TYPE_INT24:
+ field_length= field->max_length() - 1;
+ break;
+ case FIELD_TYPE_BIT:
+ field_length= field->max_length();
+ decimals= -1; // return NULL
+ break;
+ case FIELD_TYPE_FLOAT:
+ case FIELD_TYPE_DOUBLE:
+ field_length= field->field_length;
+ if (decimals == NOT_FIXED_DEC)
+ decimals= -1; // return NULL
+ break;
+ default:
+ field_length= decimals= -1;
+ break;
+ }
+
+ if (field_length >= 0)
+ {
+ table->field[10]->store((longlong) field_length);
+ table->field[10]->set_notnull();
}
+ if (decimals >= 0)
+ {
+ table->field[11]->store((longlong) decimals);
+ table->field[11]->set_notnull();
+ }
+
+ if (field->has_charset())
+ {
+ pos=(byte*) field->charset()->csname;
+ table->field[12]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ table->field[12]->set_notnull();
+ pos=(byte*) field->charset()->name;
+ table->field[13]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ table->field[13]->set_notnull();
+ }
+ pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
+ (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
+ (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
+ table->field[15]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+
+ end= tmp;
+ if (field->unireg_check == Field::NEXT_NUMBER)
+ end=strmov(tmp,"auto_increment");
+ table->field[16]->store(tmp, (uint) (end-tmp), cs);
+
+ table->field[18]->store(field->comment.str, field->comment.length, cs);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
@@ -2580,7 +2614,8 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+
+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++)
{
CHARSET_INFO *tmp_cs= cs[0];
if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
@@ -2588,12 +2623,12 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
!(wild && wild[0] &&
wild_case_compare(scs, tmp_cs->csname,wild)))
{
+ const char *comment;
restore_record(table, s->default_values);
table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
- table->field[2]->store(tmp_cs->comment ? tmp_cs->comment : "",
- strlen(tmp_cs->comment ? tmp_cs->comment : ""),
- scs);
+ comment= tmp_cs->comment ? tmp_cs->comment : "";
+ table->field[2]->store(comment, strlen(comment), scs);
table->field[3]->store((longlong) tmp_cs->mbmaxlen);
if (schema_table_store_record(thd, table))
return 1;
@@ -2609,14 +2644,14 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
{
CHARSET_INFO **cl;
CHARSET_INFO *tmp_cs= cs[0];
if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
- for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
+ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
@@ -2649,14 +2684,14 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
CHARSET_INFO **cs;
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
{
CHARSET_INFO **cl;
CHARSET_INFO *tmp_cs= cs[0];
if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
- for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
+ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
@@ -2749,12 +2784,14 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE_LIST proc_tables;
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
int res= 0;
- TABLE *table= tables->table, *old_open_tables= thd->open_tables;
+ TABLE *table= tables->table;
bool full_access;
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
+ Open_tables_state open_tables_state_backup;
DBUG_ENTER("fill_schema_proc");
strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
+ /* We use this TABLE_LIST instance only for checking of privileges. */
bzero((char*) &proc_tables,sizeof(proc_tables));
proc_tables.db= (char*) "mysql";
proc_tables.db_length= 5;
@@ -2762,7 +2799,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
- if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
+ if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
{
DBUG_RETURN(1);
}
@@ -2788,7 +2825,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
err:
proc_table->file->ha_index_end();
- close_thread_tables(thd, 0, 0, old_open_tables);
+ close_proc_table(thd, &open_tables_state_backup);
DBUG_RETURN(res);
}
@@ -3192,7 +3229,8 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
CHARSET_INFO *cs= system_charset_info;
OPEN_TABLE_LIST *open_list;
- if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
+ if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
+ && thd->is_fatal_error)
DBUG_RETURN(1);
for (; open_list ; open_list=open_list->next)
@@ -3258,7 +3296,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
ST_SCHEMA_TABLE *schema_table= schema_tables;
- for ( ; schema_table->table_name; schema_table++)
+ for (; schema_table->table_name; schema_table++)
{
if (!my_strcasecmp(system_charset_info,
schema_table->table_name,
@@ -3299,7 +3337,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
CHARSET_INFO *cs= system_charset_info;
DBUG_ENTER("create_schema_table");
- for ( ; fields_info->field_name; fields_info++)
+ for (; fields_info->field_name; fields_info++)
{
switch (fields_info->field_type) {
case MYSQL_TYPE_LONG:
@@ -3368,7 +3406,7 @@ int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= schema_table->fields_info;
Name_resolution_context *context= &thd->lex->select_lex.context;
- for ( ; field_info->field_name; field_info++)
+ for (; field_info->field_name; field_info++)
{
if (field_info->old_name)
{
@@ -3554,7 +3592,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
{
DBUG_RETURN(1);
}
- table->s->tmp_table= TMP_TABLE;
+ table->s->tmp_table= SYSTEM_TMP_TABLE;
table->grant.privilege= SELECT_ACL;
/*
This test is necessary to make
@@ -3685,11 +3723,6 @@ bool get_schema_tables_result(JOIN *join)
TABLE_LIST *table_list= tab->table->pos_in_table_list;
if (table_list->schema_table && thd->fill_derived_tables())
{
- TABLE_LIST **query_tables_last= lex->query_tables_last;
- TABLE *old_derived_tables= thd->derived_tables;
- MYSQL_LOCK *sql_lock= thd->lock;
- lex->sql_command= SQLCOM_SHOW_FIELDS;
- DBUG_ASSERT(!*query_tables_last);
if (&lex->unit != lex->current_select->master_unit()) // is subselect
{
table_list->table->file->extra(HA_EXTRA_RESET_STATE);
@@ -3700,16 +3733,9 @@ bool get_schema_tables_result(JOIN *join)
else
table_list->table->file->records= 0;
- thd->derived_tables= 0;
- thd->lock=0;
if (table_list->schema_table->fill_table(thd, table_list,
tab->select_cond))
result= 1;
- thd->lock= sql_lock;
- lex->sql_command= SQLCOM_SELECT;
- thd->derived_tables= old_derived_tables;
- lex->query_tables_last= query_tables_last;
- *query_tables_last= 0;
}
}
thd->no_warnings_for_error= 0;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6f2f1bf344f..d20908c9f1c 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -288,6 +288,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
for (table= tables; table; table= table->next_local)
{
char *db=table->db;
+ table->was_dropped= 0;
mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL);
if (!close_temporary_table(thd, db, table->table_name))
{
@@ -359,6 +360,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
wrong_tables.append(',');
wrong_tables.append(String(table->table_name,system_charset_info));
}
+ else
+ table->was_dropped= 1;
}
thd->tmp_table_used= tmp_table_deleted;
error= 0;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 722568e7f53..ddd0f3fe162 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -370,7 +370,7 @@ static void display_table_locks(void)
VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
VOID(pthread_mutex_lock(&THR_LOCK_lock));
- for (list=thr_lock_thread_list ; list ; list=rest(list))
+ for (list= thr_lock_thread_list; list; list= list_rest(list))
{
THR_LOCK *lock=(THR_LOCK*) list->data;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 09eeff02de6..053dfdfc990 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -869,3 +869,39 @@ end:
free_root(&table.mem_root, MYF(0));
DBUG_RETURN(result);
}
+
+
+
+bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
+ trg_action_time_type time_type,
+ bool old_row_is_record1)
+{
+ int res= 0;
+
+ if (bodies[event][time_type])
+ {
+ Sub_statement_state statement_state;
+
+ if (old_row_is_record1)
+ {
+ old_field= record1_field;
+ new_field= table->field;
+ }
+ else
+ {
+ new_field= record1_field;
+ old_field= table->field;
+ }
+
+ /*
+ FIXME: We should juggle with security context here (because trigger
+ should be invoked with creator rights).
+ */
+
+ thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
+ res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
+ thd->restore_sub_statement_state(&statement_state);
+ }
+
+ return res;
+}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index e2ed4bcc0f4..d9b39cc3034 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -20,6 +20,7 @@
QQ: Will it be merged into TABLE in future ?
*/
+
class Table_triggers_list: public Sql_alloc
{
/* Triggers as SPs grouped by event, action_time */
@@ -76,55 +77,7 @@ public:
bool drop_trigger(THD *thd, TABLE_LIST *table);
bool process_triggers(THD *thd, trg_event_type event,
trg_action_time_type time_type,
- bool old_row_is_record1)
- {
- int res= 0;
-
- if (bodies[event][time_type])
- {
- bool save_in_sub_stmt= thd->in_sub_stmt;
-#ifndef EMBEDDED_LIBRARY
- /* Surpress OK packets in case if we will execute statements */
- my_bool nsok= thd->net.no_send_ok;
- thd->net.no_send_ok= TRUE;
-#endif
-
- if (old_row_is_record1)
- {
- old_field= record1_field;
- new_field= table->field;
- }
- else
- {
- new_field= record1_field;
- old_field= table->field;
- }
-
- /*
- FIXME: We should juggle with security context here (because trigger
- should be invoked with creator rights).
- */
- /*
- We disable binlogging, as in SP/functions, even though currently
- triggers can't do updates. When triggers can do updates, someone
- should add such a trigger to rpl_sp.test to verify that the update
- does NOT go into binlog.
- */
- tmp_disable_binlog(thd);
- thd->in_sub_stmt= TRUE;
-
- res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
-
- thd->in_sub_stmt= save_in_sub_stmt;
- reenable_binlog(thd);
-
-#ifndef EMBEDDED_LIBRARY
- thd->net.no_send_ok= nsok;
-#endif
- }
-
- return res;
- }
+ bool old_row_is_record1);
bool get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
LEX_STRING *trigger_name, LEX_STRING *trigger_stmt,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index c414f5e9e72..72c96e81682 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -119,8 +119,6 @@ void
st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
{
thd->lex->current_select= fake_select_lex;
- fake_select_lex->ftfunc_list_alloc.empty();
- fake_select_lex->ftfunc_list= &fake_select_lex->ftfunc_list_alloc;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
&result_table_list.next_local);
@@ -291,6 +289,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
List_iterator_fast<Item> tp(types);
Query_arena *arena= thd->current_arena;
Item *type;
+ ulonglong create_options;
while ((type= tp++))
{
@@ -301,15 +300,24 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
goto err;
}
}
+
+ create_options= (first_select_in_union()->options | thd_arg->options |
+ TMP_TABLE_ALL_COLUMNS);
+ /*
+ Force the temporary table to be a MyISAM table if we're going to use
+ fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading
+ from it (this should be removed in 5.2 when fulltext search is moved
+ out of MyISAM).
+ */
+ if (global_parameters->ftfunc_list->elements)
+ create_options= create_options | TMP_TABLE_FORCE_MYISAM;
union_result->tmp_table_param.field_count= types.elements;
if (!(table= create_tmp_table(thd_arg,
&union_result->tmp_table_param, types,
(ORDER*) 0, (bool) union_distinct, 1,
- (first_select_in_union()->options |
- thd_arg->options |
- TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR, (char *) tmp_table_alias)))
+ create_options, HA_POS_ERROR,
+ (char *) tmp_table_alias)))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 95d0f500df8..993b1a409ba 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -138,7 +138,7 @@ int mysql_update(THD *thd,
LINT_INIT(timestamp_query_id);
- if (open_tables(thd, &table_list, &table_count))
+ if (open_tables(thd, &table_list, &table_count, 0))
DBUG_RETURN(1);
if (table_list->multitable_view)
@@ -660,7 +660,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(thd, &select_lex->context,
+ if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
table_list, conds, &select_lex->leaf_tables,
FALSE) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
@@ -737,7 +737,8 @@ bool mysql_multi_update_prepare(THD *thd)
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
/* open tables and create derived ones, but do not lock and fill them */
- if ((original_multiupdate && open_tables(thd, &table_list, & table_count)) ||
+ if ((original_multiupdate &&
+ open_tables(thd, &table_list, &table_count, 0)) ||
mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE);
/*
@@ -747,6 +748,7 @@ bool mysql_multi_update_prepare(THD *thd)
*/
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))
DBUG_RETURN(TRUE);
@@ -865,6 +867,7 @@ bool mysql_multi_update_prepare(THD *thd)
tbl->cleanup_items();
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) ||
setup_fields_with_no_wrap(thd, 0, *fields, 2, 0, 0))
@@ -915,7 +918,7 @@ bool mysql_multi_update(THD *thd,
List<Item> *fields,
List<Item> *values,
COND *conds,
- ulong options,
+ ulonglong options,
enum enum_duplicates handle_duplicates, bool ignore,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
@@ -925,7 +928,7 @@ bool mysql_multi_update(THD *thd,
if (mysql_multi_update_prepare(thd))
DBUG_RETURN(TRUE);
- if (!(result= new multi_update(thd, table_list,
+ if (!(result= new multi_update(table_list,
thd->lex->select_lex.leaf_tables,
fields, values,
handle_duplicates, ignore)))
@@ -951,13 +954,13 @@ bool mysql_multi_update(THD *thd,
}
-multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
+multi_update::multi_update(TABLE_LIST *table_list,
TABLE_LIST *leaves_list,
List<Item> *field_list, List<Item> *value_list,
enum enum_duplicates handle_duplicates_arg,
bool ignore_arg)
:all_tables(table_list), leaves(leaves_list), update_tables(0),
- thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list),
+ tmp_tables(0), updated(0), found(0), fields(field_list),
values(value_list), table_count(0), copy_field(0),
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
transactional_tables(1), ignore(ignore_arg)
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index aedff648e5c..dcada0c0780 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -94,6 +94,67 @@ static void make_unique_view_field_name(Item *target,
target->set_name(buff, name_len, system_charset_info);
}
+
+/*
+ Check if items with same names are present in list and possibly
+ generate unique names for them.
+
+ SYNOPSIS
+ item_list list of Items which should be checked for duplicates
+ gen_unique_view_name flag: generate unique name or return with error when
+ duplicate names are found.
+
+ DESCRIPTION
+ This function is used on view creation and preparation of derived tables.
+ It checks item_list for items with duplicate names. If it founds two
+ items with same name and conversion to unique names isn't allowed, or
+ names for both items are set by user - function fails.
+ Otherwise it generates unique name for one item with autogenerated name
+ using make_unique_view_field_name()
+
+ RETURN VALUE
+ FALSE no duplicate names found, or they are converted to unique ones
+ TRUE duplicate names are found and they can't be converted or conversion
+ isn't allowed
+*/
+
+bool check_duplicate_names(List<Item> &item_list, bool gen_unique_view_name)
+{
+ Item *item;
+ List_iterator_fast<Item> it(item_list);
+ List_iterator_fast<Item> itc(item_list);
+ DBUG_ENTER("check_duplicate_names");
+
+ while ((item= it++))
+ {
+ Item *check;
+ /* treat underlying fields like set by user names */
+ if (item->real_item()->type() == Item::FIELD_ITEM)
+ item->is_autogenerated_name= FALSE;
+ itc.rewind();
+ while ((check= itc++) && check != item)
+ {
+ if (my_strcasecmp(system_charset_info, item->name, check->name) == 0)
+ {
+ if (!gen_unique_view_name)
+ goto err;
+ if (item->is_autogenerated_name)
+ make_unique_view_field_name(item, item_list, item);
+ else if (check->is_autogenerated_name)
+ make_unique_view_field_name(check, item_list, item);
+ else
+ goto err;
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+
+err:
+ my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
+ DBUG_RETURN(TRUE);
+}
+
+
/*
Creating/altering VIEW procedure
@@ -245,9 +306,11 @@ bool mysql_create_view(THD *thd,
/*
check that tables are not temporary and this VIEW do not used in query
- (it is possible with ALTERing VIEW)
- */
- for (tbl= tables; tbl; tbl= tbl->next_global)
+ (it is possible with ALTERing VIEW).
+ open_and_lock_tables can change the value of tables,
+ e.g. it may happen if before the function call tables was equal to 0.
+ */
+ for (tbl= lex->query_tables; tbl; tbl= tbl->next_global)
{
/* is this table temporary and is not view? */
if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view &&
@@ -308,35 +371,8 @@ bool mysql_create_view(THD *thd,
}
}
- /* Test absence of duplicates names */
- {
- Item *item;
- List_iterator_fast<Item> it(select_lex->item_list);
- List_iterator_fast<Item> itc(select_lex->item_list);
- while ((item= it++))
- {
- Item *check;
- /* treat underlying fields like set by user names */
- if (item->real_item()->type() == Item::FIELD_ITEM)
- item->is_autogenerated_name= FALSE;
- itc.rewind();
- while ((check= itc++) && check != item)
- {
- if (my_strcasecmp(system_charset_info, item->name, check->name) == 0)
- {
- if (item->is_autogenerated_name)
- make_unique_view_field_name(item, select_lex->item_list, item);
- else if (check->is_autogenerated_name)
- make_unique_view_field_name(check, select_lex->item_list, item);
- else
- {
- my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
- DBUG_RETURN(TRUE);
- }
- }
- }
- }
- }
+ if (check_duplicate_names(select_lex->item_list, 1))
+ DBUG_RETURN(TRUE);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
@@ -844,6 +880,9 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
view_tables);
lex->select_lex.context.outer_context= 0;
lex->select_lex.context.select_lex= table->select_lex;
+ lex->select_lex.select_n_having_items+=
+ table->select_lex->select_n_having_items;
+
/* do not check privileges & hide errors for view underlyings */
for (SELECT_LEX *sl= lex->all_selects_list;
sl;
@@ -864,7 +903,11 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
if (view_tables->next_local)
+ {
table->multitable_view= TRUE;
+ if (table->belong_to_view)
+ table->belong_to_view->multitable_view= TRUE;
+ }
/* make nested join structure for view tables */
NESTED_JOIN *nested_join;
if (!(nested_join= table->nested_join=
@@ -1110,7 +1153,10 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
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;
return TRUE;
+ }
}
thd->set_query_id= save_set_query_id;
}
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 3246dbae383..9d961feb143 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -33,5 +33,7 @@ int view_checksum(THD *thd, TABLE_LIST *view);
extern TYPELIB updatable_views_with_limit_typelib;
+bool check_duplicate_names(List<Item>& item_list, bool gen_unique_view_names);
+
#define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6dd808006c3..9cda6efca06 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -592,6 +592,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SUM_SYM
%token SUPER_SYM
%token SUSPEND_SYM
+%token SYSDATE
%token TABLES
%token TABLESPACE
%token TABLE_SYM
@@ -730,7 +731,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
bool_term bool_factor bool_test bool_pri
predicate bit_expr bit_term bit_factor value_expr term factor
table_wild simple_expr udf_expr
- using_list expr_or_default set_expr_or_default interval_expr
+ expr_or_default set_expr_or_default interval_expr
param_marker singlerow_subselect singlerow_subselect_init
exists_subselect exists_subselect_init geometry_function
signed_literal now_or_signed_literal opt_escape
@@ -753,7 +754,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
key_alg opt_btree_or_rtree
%type <string_list>
- key_usage_list
+ key_usage_list using_list
%type <key_part>
key_part
@@ -1327,6 +1328,12 @@ create:
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
sp->restore_thd_mem_root(YYTHD);
+ if (sp->m_multi_results)
+ {
+ my_error(ER_SP_NO_RETSET, MYF(0), "trigger");
+ YYABORT;
+ }
+
/*
We have to do it after parsing trigger body, because some of
sp_proc_stmt alternatives are not saving/restoring LEX, so
@@ -1479,8 +1486,7 @@ create_function_tail:
if (sp->m_multi_results)
{
- my_message(ER_SP_NO_RETSET_IN_FUNC, ER(ER_SP_NO_RETSET_IN_FUNC),
- MYF(0));
+ my_error(ER_SP_NO_RETSET, MYF(0), "function");
YYABORT;
}
if (sp->check_backpatch(YYTHD))
@@ -1976,7 +1982,7 @@ sp_proc_stmt:
}
if (lex->sql_command == SQLCOM_CHANGE_DB)
{ /* "USE db" doesn't work in a procedure */
- my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0));
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "USE");
YYABORT;
}
/*
@@ -5007,10 +5013,10 @@ simple_expr:
my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
YYABORT;
}
- $$= new Item_default_value(&Select->context, $3);
+ $$= new Item_default_value(Lex->current_context(), $3);
}
| VALUES '(' simple_ident ')'
- { $$= new Item_insert_value(&Select->context, $3); }
+ { $$= new Item_insert_value(Lex->current_context(), $3); }
| FUNC_ARG0 '(' ')'
{
if (!$1.symbol->create_func)
@@ -5265,6 +5271,10 @@ simple_expr:
{ $$= new Item_func_substr($3,$5); }
| SUBSTRING_INDEX '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_substr_index($3,$5,$7); }
+ | SYSDATE optional_braces
+ { $$= new Item_func_sysdate_local(); Lex->safe_to_cache_query=0;}
+ | SYSDATE '(' expr ')'
+ { $$= new Item_func_sysdate_local($3); Lex->safe_to_cache_query=0;}
| TIME_SYM '(' expr ')'
{ $$= new Item_time_typecast($3); }
| TIMESTAMP '(' expr ')'
@@ -5301,9 +5311,9 @@ simple_expr:
name->init_qname(YYTHD);
sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
if ($5)
- $$= new Item_func_sp(&lex->current_select->context, name, *$5);
+ $$= new Item_func_sp(Lex->current_context(), name, *$5);
else
- $$= new Item_func_sp(&lex->current_select->context, name);
+ $$= new Item_func_sp(Lex->current_context(), name);
lex->safe_to_cache_query=0;
}
| IDENT_sys '(' udf_expr_list ')'
@@ -5391,9 +5401,9 @@ simple_expr:
sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
if ($3)
- $$= new Item_func_sp(&lex->current_select->context, name, *$3);
+ $$= new Item_func_sp(Lex->current_context(), name, *$3);
else
- $$= new Item_func_sp(&lex->current_select->context, name);
+ $$= new Item_func_sp(Lex->current_context(), name);
lex->safe_to_cache_query=0;
}
}
@@ -5597,7 +5607,7 @@ sum_expr:
{
SELECT_LEX *sel= Select;
sel->in_sum_expr--;
- $$=new Item_func_group_concat(&sel->context, $3, $5,
+ $$=new Item_func_group_concat(Lex->current_context(), $3, $5,
sel->gorder_list, $7);
$5->empty();
};
@@ -5733,68 +5743,116 @@ join_table:
table_ref normal_join table_ref { YYERROR_UNLESS($1 && ($$=$3)); }
| table_ref STRAIGHT_JOIN table_factor
{ YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
- | table_ref normal_join table_ref ON expr
- { YYERROR_UNLESS($1 && ($$=$3)); add_join_on($3,$5); }
- | table_ref STRAIGHT_JOIN table_factor ON expr
- { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; add_join_on($3,$5); }
+ | table_ref normal_join table_ref
+ ON
+ {
+ YYERROR_UNLESS($1 && ($$=$3));
+ /* Change the current name resolution context to a local context. */
+ Name_resolution_context *on_context;
+ if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
+ YYABORT;
+ Lex->push_context(on_context);
+ }
+ expr
+ {
+ add_join_on($3,$6);
+ Lex->pop_context();
+ }
+ | table_ref STRAIGHT_JOIN table_factor
+ ON
+ {
+ YYERROR_UNLESS($1 && ($$=$3));
+ /* Change the current name resolution context to a local context. */
+ Name_resolution_context *on_context;
+ if (!(on_context= make_join_on_context(YYTHD,$1,$3)))
+ YYABORT;
+ Lex->push_context(on_context);
+ }
+ expr
+ {
+ $3->straight=1;
+ add_join_on($3,$6);
+ Lex->pop_context();
+ }
| table_ref normal_join table_ref
USING
{
SELECT_LEX *sel= Select;
YYERROR_UNLESS($1 && $3);
- sel->save_names_for_using_list($1, $3);
}
'(' using_list ')'
- { add_join_on($3,$7); $$=$3; }
-
- | table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
- { YYERROR_UNLESS($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ { add_join_natural($1,$3,$7); $$=$3; }
+ | table_ref LEFT opt_outer JOIN_SYM table_ref
+ ON
+ {
+ /* Change the current name resolution context to a local context. */
+ Name_resolution_context *on_context;
+ if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
+ YYABORT;
+ Lex->push_context(on_context);
+ }
+ expr
+ {
+ YYERROR_UNLESS($1 && $5);
+ add_join_on($5,$8);
+ Lex->pop_context();
+ $5->outer_join|=JOIN_TYPE_LEFT;
+ $$=$5;
+ }
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
YYERROR_UNLESS($1 && $5);
- sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
- { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
YYERROR_UNLESS($1 && $6);
- add_join_natural($1,$6);
+ add_join_natural($1,$6,NULL);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
- | table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
+ | table_ref RIGHT opt_outer JOIN_SYM table_ref
+ ON
+ {
+ /* Change the current name resolution context to a local context. */
+ Name_resolution_context *on_context;
+ if (!(on_context= make_join_on_context(YYTHD,$1,$5)))
+ YYABORT;
+ Lex->push_context(on_context);
+ }
+ expr
{
LEX *lex= Lex;
YYERROR_UNLESS($1 && $5);
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
- add_join_on($$, $7);
+ add_join_on($$, $8);
+ Lex->pop_context();
}
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
YYERROR_UNLESS($1 && $5);
- sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
- add_join_on($$, $9);
+ add_join_natural($$,$5,$9);
}
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
YYERROR_UNLESS($1 && $6);
- add_join_natural($6,$1);
+ add_join_natural($6,$1,NULL);
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
}
| table_ref NATURAL JOIN_SYM table_factor
- { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4); };
+ { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4,NULL); };
normal_join:
@@ -5822,8 +5880,23 @@ table_factor:
YYABORT;
sel->add_joined_table($$);
}
- | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
- { YYERROR_UNLESS($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
+ ON
+ {
+ /* Change the current name resolution context to a local context. */
+ Name_resolution_context *on_context;
+ if (!(on_context= make_join_on_context(YYTHD,$3,$7)))
+ YYABORT;
+ Lex->push_context(on_context);
+ }
+ expr '}'
+ {
+ YYERROR_UNLESS($3 && $7);
+ add_join_on($7,$10);
+ Lex->pop_context();
+ $7->outer_join|=JOIN_TYPE_LEFT;
+ $$=$7;
+ }
| select_derived_init get_select_lex select_derived2
{
LEX *lex= Lex;
@@ -5877,6 +5950,7 @@ table_factor:
YYABORT;
sel->add_joined_table($$);
+ lex->pop_context();
}
else
if ($4 || $6)
@@ -6016,32 +6090,18 @@ key_usage_list2:
using_list:
ident
{
- SELECT_LEX *sel= Select;
- if (!($$= new Item_func_eq(new Item_field(&sel->context,
- sel->db1, sel->table1,
- $1.str),
- new Item_field(&sel->context,
- sel->db2, sel->table2,
- $1.str))))
+ if (!($$= new List<String>))
YYABORT;
+ $$->push_back(new (YYTHD->mem_root)
+ String((const char *) $1.str, $1.length,
+ system_charset_info));
}
| using_list ',' ident
{
- SELECT_LEX *sel= Select;
- if (!($$=
- new Item_cond_and(new
- Item_func_eq(new
- Item_field(&sel->context,
- sel->db1,
- sel->table1,
- $3.str),
- new
- Item_field(&sel->context,
- sel->db2,
- sel->table2,
- $3.str)),
- $1)))
- YYABORT;
+ $1->push_back(new (YYTHD->mem_root)
+ String((const char *) $3.str, $3.length,
+ system_charset_info));
+ $$= $1;
};
interval:
@@ -6682,7 +6742,7 @@ values:
expr_or_default:
expr { $$= $1;}
- | DEFAULT {$$= new Item_default_value(&Select->context); }
+ | DEFAULT {$$= new Item_default_value(Lex->current_context()); }
;
opt_insert_update:
@@ -7229,9 +7289,14 @@ flush:
FLUSH_SYM opt_no_write_to_binlog
{
LEX *lex=Lex;
- if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_FUNCTION)
+ if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
{
- my_error(ER_SP_BADSTATEMENT, MYF(0), "FLUSH");
+ /*
+ Note that both FLUSH TABLES and FLUSH PRIVILEGES will break
+ execution in prelocked mode. So it is better to disable
+ FLUSH in stored functions and triggers completely.
+ */
+ my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
YYABORT;
}
lex->sql_command= SQLCOM_FLUSH; lex->type=0;
@@ -7638,13 +7703,13 @@ table_wild:
ident '.' '*'
{
SELECT_LEX *sel= Select;
- $$ = new Item_field(&sel->context, NullS, $1.str, "*");
+ $$ = new Item_field(Lex->current_context(), NullS, $1.str, "*");
sel->with_wild++;
}
| ident '.' ident '.' '*'
{
SELECT_LEX *sel= Select;
- $$ = new Item_field(&sel->context, (YYTHD->client_capabilities &
+ $$ = new Item_field(Lex->current_context(), (YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str,"*");
sel->with_wild++;
@@ -7672,8 +7737,8 @@ simple_ident:
SELECT_LEX *sel=Select;
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) :
- (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str);
+ (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) :
+ (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str);
}
}
| simple_ident_q { $$= $1; }
@@ -7685,8 +7750,8 @@ simple_ident_nospvar:
SELECT_LEX *sel=Select;
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) :
- (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str);
+ (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) :
+ (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str);
}
| simple_ident_q { $$= $1; }
;
@@ -7723,7 +7788,7 @@ simple_ident_q:
YYABORT;
}
- if (!(trg_fld= new Item_trigger_field(&lex->current_select->context,
+ if (!(trg_fld= new Item_trigger_field(Lex->current_context(),
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
@@ -7749,8 +7814,8 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) :
- (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str);
+ (Item*) new Item_field(Lex->current_context(), NullS, $1.str, $3.str) :
+ (Item*) new Item_ref(Lex->current_context(), NullS, $1.str, $3.str);
}
}
| '.' ident '.' ident
@@ -7765,8 +7830,8 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) :
- (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str);
+ (Item*) new Item_field(Lex->current_context(), NullS, $2.str, $4.str) :
+ (Item*) new Item_ref(Lex->current_context(), NullS, $2.str, $4.str);
}
| ident '.' ident '.' ident
{
@@ -7780,11 +7845,11 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(&sel->context,
+ (Item*) new Item_field(Lex->current_context(),
(YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str, $5.str) :
- (Item*) new Item_ref(&sel->context,
+ (Item*) new Item_ref(Lex->current_context(),
(YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str, $5.str);
@@ -8345,7 +8410,8 @@ sys_option_value:
/* We are in trigger and assigning value to field of new row */
Item *it;
Item_trigger_field *trg_fld;
- sp_instr_set_trigger_field *i;
+ sp_instr_set_trigger_field *sp_fld;
+ LINT_INIT(sp_fld);
if ($1)
{
yyerror(ER(ER_SYNTAX_ERROR));
@@ -8359,14 +8425,14 @@ sys_option_value:
it= new Item_null();
}
- if (!(trg_fld= new Item_trigger_field(&lex->current_select->
- context,
+ if (!(trg_fld= new Item_trigger_field(Lex->current_context(),
Item_trigger_field::NEW_ROW,
$2.base_name.str)) ||
- !(i= new sp_instr_set_trigger_field(lex->sphead->
- instructions(),
- lex->spcont, trg_fld,
- it, lex)))
+ !(sp_fld= new sp_instr_set_trigger_field(lex->sphead->
+ instructions(),
+ lex->spcont,
+ trg_fld,
+ it, lex)))
YYABORT;
/*
@@ -8376,7 +8442,7 @@ sys_option_value:
lex->trg_table_fields.link_in_list((byte *)trg_fld,
(byte **)&trg_fld->next_trg_field);
- lex->sphead->add_instr(i);
+ lex->sphead->add_instr(sp_fld);
}
else if ($2.var)
{ /* System variable */
@@ -8390,7 +8456,7 @@ sys_option_value:
/* An SP local variable */
sp_pcontext *ctx= lex->spcont;
sp_pvar_t *spv;
- sp_instr_set *i;
+ sp_instr_set *sp_set;
Item *it;
if ($1)
{
@@ -8406,9 +8472,9 @@ sys_option_value:
it= spv->dflt;
else
it= new Item_null();
- i= new sp_instr_set(lex->sphead->instructions(), ctx,
- spv->offset, it, spv->type, lex, TRUE);
- lex->sphead->add_instr(i);
+ sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
+ spv->offset, it, spv->type, lex, TRUE);
+ lex->sphead->add_instr(sp_set);
spv->isset= TRUE;
}
}
@@ -9216,7 +9282,14 @@ union_list:
lex->current_select->master_unit()->union_distinct=
lex->current_select;
}
- select_init {}
+ select_init
+ {
+ /*
+ Remove from the name resolution context stack the context of the
+ last select in the union.
+ */
+ Lex->pop_context();
+ }
;
union_opt:
@@ -9320,6 +9393,7 @@ subselect_end:
')'
{
LEX *lex=Lex;
+ lex->pop_context();
lex->current_select = lex->current_select->return_after_parsing();
};
@@ -9371,7 +9445,7 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume
{
Lex->sql_command = SQLCOM_XA_START;
}
- | XA_SYM END xid opt_suspend_or_migrate
+ | XA_SYM END xid opt_suspend
{
Lex->sql_command = SQLCOM_XA_END;
}
@@ -9431,9 +9505,14 @@ opt_one_phase:
| ONE_SYM PHASE_SYM { Lex->xa_opt=XA_ONE_PHASE; }
;
-opt_suspend_or_migrate:
+opt_suspend:
/* nothing */ { Lex->xa_opt=XA_NONE; }
| SUSPEND_SYM { Lex->xa_opt=XA_SUSPEND; }
+ opt_migrate
+ ;
+
+opt_migrate:
+ /* nothing */ { }
| FOR_SYM MIGRATE_SYM { Lex->xa_opt=XA_FOR_MIGRATE; }
;
diff --git a/sql/table.cc b/sql/table.cc
index 7c1701cc4d3..810ade44b6c 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1755,8 +1755,6 @@ void st_table_list::set_ancestor()
*/
tbl->ancestor->set_ancestor();
}
- if (tbl->multitable_view)
- multitable_view= TRUE;
} while ((tbl= tbl->next_local));
if (!multitable_view)
@@ -2182,8 +2180,290 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
}
+/*
+ Test if this is a leaf with respect to name resolution.
+
+ SYNOPSIS
+ st_table_list::is_leaf_for_name_resolution()
+
+ DESCRIPTION
+ A table reference is a leaf with respect to name resolution if
+ it is either a leaf node in a nested join tree (table, view,
+ schema table, subquery), or an inner node that represents a
+ NATURAL/USING join, or a nested join with materialized join
+ columns.
+
+ RETURN
+ TRUE if a leaf, FALSE otherwise.
+*/
+bool st_table_list::is_leaf_for_name_resolution()
+{
+ return (view || is_natural_join || is_join_columns_complete ||
+ !nested_join);
+}
+
+
+/*
+ Retrieve the first (left-most) leaf in a nested join tree with
+ respect to name resolution.
+
+ SYNOPSIS
+ st_table_list::first_leaf_for_name_resolution()
+
+ DESCRIPTION
+ Given that 'this' is a nested table reference, recursively walk
+ down the left-most children of 'this' until we reach a leaf
+ table reference with respect to name resolution.
+
+ IMPLEMENTATION
+ The left-most child of a nested table reference is the last element
+ in the list of children because the children are inserted in
+ reverse order.
+
+ RETURN
+ If 'this' is a nested table reference - the left-most child of
+ the tree rooted in 'this',
+ else return 'this'
+*/
+
+TABLE_LIST *st_table_list::first_leaf_for_name_resolution()
+{
+ TABLE_LIST *cur_table_ref;
+ NESTED_JOIN *cur_nested_join;
+ LINT_INIT(cur_table_ref);
+
+ if (is_leaf_for_name_resolution())
+ return this;
+ DBUG_ASSERT(nested_join);
+
+ for (cur_nested_join= nested_join;
+ cur_nested_join;
+ cur_nested_join= cur_table_ref->nested_join)
+ {
+ List_iterator_fast<TABLE_LIST> it(cur_nested_join->join_list);
+ cur_table_ref= it++;
+ /*
+ If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse
+ order, thus the first operand is already at the front of the list.
+ */
+ if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
+ {
+ TABLE_LIST *next;
+ while ((next= it++))
+ cur_table_ref= next;
+ }
+ if (cur_table_ref->is_leaf_for_name_resolution())
+ break;
+ }
+ return cur_table_ref;
+}
+
+
+/*
+ Retrieve the last (right-most) leaf in a nested join tree with
+ respect to name resolution.
+
+ SYNOPSIS
+ st_table_list::last_leaf_for_name_resolution()
+
+ DESCRIPTION
+ Given that 'this' is a nested table reference, recursively walk
+ down the right-most children of 'this' until we reach a leaf
+ table reference with respect to name resolution.
+
+ IMPLEMENTATION
+ The right-most child of a nested table reference is the first
+ element in the list of children because the children are inserted
+ in reverse order.
+
+ RETURN
+ - If 'this' is a nested table reference - the right-most child of
+ the tree rooted in 'this',
+ - else - 'this'
+*/
+
+TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
+{
+ TABLE_LIST *cur_table_ref= this;
+ NESTED_JOIN *cur_nested_join;
+
+ if (is_leaf_for_name_resolution())
+ return this;
+ DBUG_ASSERT(nested_join);
+
+ for (cur_nested_join= nested_join;
+ cur_nested_join;
+ cur_nested_join= cur_table_ref->nested_join)
+ {
+ /*
+ If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse
+ order, thus the last operand is in the end of the list.
+ */
+ if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
+ {
+ List_iterator_fast<TABLE_LIST> it(cur_nested_join->join_list);
+ TABLE_LIST *next;
+ cur_table_ref= it++;
+ while ((next= it++))
+ cur_table_ref= next;
+ }
+ else
+ cur_table_ref= cur_nested_join->join_list.head();
+ if (cur_table_ref->is_leaf_for_name_resolution())
+ break;
+ }
+ return cur_table_ref;
+}
+
+
+Natural_join_column::Natural_join_column(Field_translator *field_param,
+ TABLE_LIST *tab)
+{
+ DBUG_ASSERT(tab->field_translation);
+ view_field= field_param;
+ table_field= NULL;
+ table_ref= tab;
+ is_common= FALSE;
+}
+
+
+Natural_join_column::Natural_join_column(Field *field_param,
+ TABLE_LIST *tab)
+{
+ DBUG_ASSERT(tab->table == field_param->table);
+ table_field= field_param;
+ view_field= NULL;
+ table_ref= tab;
+ is_common= FALSE;
+}
+
+
+const char *Natural_join_column::name()
+{
+ if (view_field)
+ {
+ DBUG_ASSERT(table_field == NULL);
+ return view_field->name;
+ }
+
+ return table_field->field_name;
+}
+
+
+Item *Natural_join_column::create_item(THD *thd)
+{
+ if (view_field)
+ {
+ DBUG_ASSERT(table_field == NULL);
+ return create_view_field(thd, table_ref, &view_field->item,
+ view_field->name);
+ }
+ return new Item_field(thd, &thd->lex->current_select->context, table_field);
+}
+
+
+Field *Natural_join_column::field()
+{
+ if (view_field)
+ {
+ DBUG_ASSERT(table_field == NULL);
+ return NULL;
+ }
+ return table_field;
+}
+
+
+const char *Natural_join_column::table_name()
+{
+ return table_ref->alias;
+ /*
+ TODO:
+ I think that it is sufficient to return just
+ table->alias, which is correctly set to either
+ the view name, the table name, or the alias to
+ the table reference (view or stored table).
+ */
+#ifdef NOT_YET
+ if (view_field)
+ return table_ref->view_name.str;
+
+ DBUG_ASSERT(!strcmp(table_ref->table_name,
+ table_ref->table->s->table_name));
+ return table_ref->table_name;
+}
+#endif
+}
+
+
+const char *Natural_join_column::db_name()
+{
+ if (view_field)
+ return table_ref->view_db.str;
+
+ DBUG_ASSERT(!strcmp(table_ref->db,
+ table_ref->table->s->db));
+ return table_ref->db;
+}
+
+
+GRANT_INFO *Natural_join_column::grant()
+{
+ if (view_field)
+ return &(table_ref->grant);
+ return &(table_ref->table->grant);
+}
+
+
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+
+/*
+ Check the access rights for the current join column.
+ columns.
+
+ SYNOPSIS
+ Natural_join_column::check_grants()
+
+ DESCRIPTION
+ Check the access rights to a column from a natural join in a generic
+ way that hides the heterogeneity of the column representation - whether
+ it is a view or a stored table colum.
+
+ RETURN
+ FALSE The column can be accessed
+ TRUE There are no access rights to all equivalent columns
+*/
+
+bool
+Natural_join_column::check_grants(THD *thd, const char *name, uint length)
+{
+ GRANT_INFO *grant;
+ const char *db_name;
+ const char *table_name;
+
+ if (view_field)
+ {
+ DBUG_ASSERT(table_field == NULL);
+ grant= &(table_ref->grant);
+ db_name= table_ref->view_db.str;
+ table_name= table_ref->view_name.str;
+ }
+ else
+ {
+ DBUG_ASSERT(table_field && view_field == NULL);
+ grant= &(table_ref->table->grant);
+ db_name= table_ref->table->s->db;
+ table_name= table_ref->table->s->table_name;
+ }
+
+ return check_grant_column(thd, grant, db_name, table_name, name, length);
+}
+#endif
+
+
void Field_iterator_view::set(TABLE_LIST *table)
{
+ DBUG_ASSERT(table->field_translation);
view= table;
ptr= table->field_translation;
array_end= table->field_translation_end;
@@ -2253,6 +2533,197 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
}
+void Field_iterator_natural_join::set(TABLE_LIST *table_ref)
+{
+ DBUG_ASSERT(table_ref->join_columns);
+ delete column_ref_it;
+
+ /*
+ TODO: try not to allocate new iterator every time. If we have to,
+ then check for out of memory condition.
+ */
+ column_ref_it= new List_iterator_fast<Natural_join_column>
+ (*(table_ref->join_columns));
+ cur_column_ref= (*column_ref_it)++;
+}
+
+
+void Field_iterator_natural_join::next()
+{
+ cur_column_ref= (*column_ref_it)++;
+ DBUG_ASSERT(!cur_column_ref || ! cur_column_ref->table_field ||
+ cur_column_ref->table_ref->table ==
+ cur_column_ref->table_field->table);
+}
+
+
+void Field_iterator_table_ref::set_field_iterator()
+{
+ DBUG_ENTER("Field_iterator_table_ref::set_field_iterator");
+ /*
+ If the table reference we are iterating over is a natural join, or it is
+ an operand of a natural join, and TABLE_LIST::join_columns contains all
+ the columns of the join operand, then we pick the columns from
+ TABLE_LIST::join_columns, instead of the orginial container of the
+ columns of the join operator.
+ */
+ if (table_ref->is_join_columns_complete)
+ {
+ /* Necesary, but insufficient conditions. */
+ DBUG_ASSERT(table_ref->is_natural_join ||
+ table_ref->nested_join ||
+ table_ref->join_columns &&
+ /* This is a merge view. */
+ ((table_ref->field_translation &&
+ table_ref->join_columns->elements ==
+ (ulong)(table_ref->field_translation_end -
+ table_ref->field_translation)) ||
+ /* This is stored table or a tmptable view. */
+ (!table_ref->field_translation &&
+ table_ref->join_columns->elements ==
+ table_ref->table->s->fields)));
+ field_it= &natural_join_it;
+ DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join",
+ table_ref->alias));
+ }
+ /* This is a merge view, so use field_translation. */
+ else if (table_ref->field_translation)
+ {
+ DBUG_ASSERT(table_ref->view &&
+ table_ref->effective_algorithm == VIEW_ALGORITHM_MERGE);
+ field_it= &view_field_it;
+ DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view",
+ table_ref->alias));
+ }
+ /* This is a base table or stored view. */
+ else
+ {
+ DBUG_ASSERT(table_ref->table || table_ref->view);
+ field_it= &table_field_it;
+ DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_table",
+ table_ref->alias));
+ }
+ field_it->set(table_ref);
+ DBUG_VOID_RETURN;
+}
+
+
+void Field_iterator_table_ref::set(TABLE_LIST *table)
+{
+ DBUG_ASSERT(table);
+ first_leaf= table->first_leaf_for_name_resolution();
+ last_leaf= table->last_leaf_for_name_resolution();
+ DBUG_ASSERT(first_leaf && last_leaf);
+ table_ref= first_leaf;
+ set_field_iterator();
+}
+
+
+void Field_iterator_table_ref::next()
+{
+ /* Move to the next field in the current table reference. */
+ field_it->next();
+ /*
+ If all fields of the current table reference are exhausted, move to
+ the next leaf table reference.
+ */
+ if (field_it->end_of_fields() && table_ref != last_leaf)
+ {
+ table_ref= table_ref->next_name_resolution_table;
+ DBUG_ASSERT(table_ref);
+ set_field_iterator();
+ }
+}
+
+
+const char *Field_iterator_table_ref::table_name()
+{
+ if (table_ref->view)
+ return table_ref->view_name.str;
+ else if (table_ref->is_natural_join)
+ return natural_join_it.column_ref()->table_name();
+
+ DBUG_ASSERT(!strcmp(table_ref->table_name,
+ table_ref->table->s->table_name));
+ return table_ref->table_name;
+}
+
+
+const char *Field_iterator_table_ref::db_name()
+{
+ if (table_ref->view)
+ return table_ref->view_db.str;
+ else if (table_ref->is_natural_join)
+ return natural_join_it.column_ref()->db_name();
+
+ DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db));
+ return table_ref->db;
+}
+
+
+GRANT_INFO *Field_iterator_table_ref::grant()
+{
+ if (table_ref->view)
+ return &(table_ref->grant);
+ else if (table_ref->is_natural_join)
+ return natural_join_it.column_ref()->grant();
+ return &(table_ref->table->grant);
+}
+
+
+/*
+ Create new or return existing column reference to a column of a
+ natural/using join.
+
+ SYNOPSIS
+ Field_iterator_table_ref::get_or_create_column_ref()
+ thd [in] pointer to current thread
+ is_created [out] set to TRUE if the column was created,
+ FALSE if we return an already created colum
+
+ DESCRIPTION
+ TODO
+
+ RETURN
+ # Pointer to a column of a natural join (or its operand)
+ NULL No memory to allocate the column
+*/
+
+Natural_join_column *
+Field_iterator_table_ref::get_or_create_column_ref(THD *thd, bool *is_created)
+{
+ Natural_join_column *nj_col;
+
+ *is_created= TRUE;
+ if (field_it == &table_field_it)
+ {
+ /* The field belongs to a stored table. */
+ Field *field= table_field_it.field();
+ nj_col= new Natural_join_column(field, table_ref);
+ }
+ else if (field_it == &view_field_it)
+ {
+ /* The field belongs to a merge view or information schema table. */
+ Field_translator *translated_field= view_field_it.field_translator();
+ nj_col= new Natural_join_column(translated_field, table_ref);
+ }
+ else
+ {
+ /*
+ The field belongs to a NATURAL join, therefore the column reference was
+ already created via one of the two constructor calls above. In this case
+ we just return the already created column reference.
+ */
+ *is_created= FALSE;
+ nj_col= natural_join_it.column_ref();
+ DBUG_ASSERT(nj_col);
+ }
+ DBUG_ASSERT(!nj_col->table_field ||
+ nj_col->table_ref->table == nj_col->table_field->table);
+ return nj_col;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/table.h b/sql/table.h
index 30462d1b173..767acf8bdc8 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -50,7 +50,8 @@ typedef struct st_grant_info
ulong want_privilege;
} GRANT_INFO;
-enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2};
+enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2,
+ SYSTEM_TMP_TABLE=3};
enum frm_type_enum
{
@@ -93,7 +94,10 @@ class Field_timestamp;
class Field_blob;
class Table_triggers_list;
-/* This structure is shared between different table objects */
+/*
+ This structure is shared between different table objects. There is one
+ instance of table share per one table in the database.
+*/
typedef struct st_table_share
{
@@ -372,9 +376,80 @@ struct Field_translator
};
+/*
+ Column reference of a NATURAL/USING join. Since column references in
+ joins can be both from views and stored tables, may point to either a
+ Field (for tables), or a Field_translator (for views).
+*/
+
+class Natural_join_column: public Sql_alloc
+{
+public:
+ Field_translator *view_field; /* Column reference of merge view. */
+ Field *table_field; /* Column reference of table or temp view. */
+ st_table_list *table_ref; /* Original base table/view reference. */
+ /*
+ True if a common join column of two NATURAL/USING join operands. Notice
+ that when we have a hierarchy of nested NATURAL/USING joins, a column can
+ be common at some level of nesting but it may not be common at higher
+ levels of nesting. Thus this flag may change depending on at which level
+ we are looking at some column.
+ */
+ bool is_common;
+public:
+ Natural_join_column(Field_translator *field_param, st_table_list *tab);
+ Natural_join_column(Field *field_param, st_table_list *tab);
+ const char *name();
+ Item *create_item(THD *thd);
+ Field *field();
+ const char *table_name();
+ const char *db_name();
+ GRANT_INFO *grant();
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool check_grants(THD *thd, const char *name, uint length);
+#endif
+};
+
+
+/*
+ Table reference in the FROM clause.
+
+ These table references can be of several types that correspond to
+ different SQL elements. Below we list all types of TABLE_LISTs with
+ the necessary conditions to determine when a TABLE_LIST instance
+ belongs to a certain type.
+
+ 1) table (TABLE_LIST::view == NULL)
+ - base table
+ (TABLE_LIST::derived == NULL)
+ - subquery - TABLE_LIST::table is a temp table
+ (TABLE_LIST::derived != NULL)
+ - information schema table
+ (TABLE_LIST::schema_table != NULL)
+ NOTICE: for schema tables TABLE_LIST::field_translation may be != NULL
+ 2) view (TABLE_LIST::view != NULL)
+ - merge (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_MERGE)
+ also (TABLE_LIST::field_translation != NULL)
+ - tmptable (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_TMPTABLE)
+ also (TABLE_LIST::field_translation == NULL)
+ 3) nested table reference (TABLE_LIST::nested_join != NULL)
+ - table sequence - e.g. (t1, t2, t3)
+ TODO: how to distinguish from a JOIN?
+ - general JOIN
+ TODO: how to distinguish from a table sequence?
+ - NATURAL JOIN
+ (TABLE_LIST::natural_join != NULL)
+ - JOIN ... USING
+ (TABLE_LIST::join_using_fields != NULL)
+*/
+
typedef struct st_table_list
{
- /* link in a local table list (used by SQL_LIST) */
+ /*
+ List of tables local to a subquery (used by SQL_LIST). Considers
+ views as leaves (unlike 'next_leaf' below). Created at parse time
+ in st_select_lex::add_table_to_list() -> table_list.link_in_list().
+ */
struct st_table_list *next_local;
/* link in a global list of all queries tables */
struct st_table_list *next_global, **prev_global;
@@ -382,7 +457,7 @@ typedef struct st_table_list
char *option; /* Used by cache index */
Item *on_expr; /* Used with outer join */
/*
- The scturcture of ON expression presented in the member above
+ The structure of ON expression presented in the member above
can be changed during certain optimizations. This member
contains a snapshot of AND-OR structure of the ON expression
made after permanent transformations of the parse tree, and is
@@ -391,10 +466,40 @@ typedef struct st_table_list
*/
Item *prep_on_expr;
COND_EQUAL *cond_equal; /* Used with outer join */
- struct st_table_list *natural_join; /* natural join on this table*/
- /* ... join ... USE INDEX ... IGNORE INDEX */
- List<String> *use_index, *ignore_index;
- TABLE *table; /* opened table */
+ /*
+ During parsing - left operand of NATURAL/USING join where 'this' is
+ the right operand. After parsing (this->natural_join == this) iff
+ 'this' represents a NATURAL or USING join operation. Thus after
+ parsing 'this' is a NATURAL/USING join iff (natural_join != NULL).
+ */
+ struct st_table_list *natural_join;
+ /*
+ True if 'this' represents a nested join that is a NATURAL JOIN.
+ For one of the operands of 'this', the member 'natural_join' points
+ to the other operand of 'this'.
+ */
+ bool is_natural_join;
+ /* Field names in a USING clause for JOIN ... USING. */
+ List<String> *join_using_fields;
+ /*
+ Explicitly store the result columns of either a NATURAL/USING join or
+ an operand of such a join.
+ */
+ List<Natural_join_column> *join_columns;
+ /* TRUE if join_columns contains all columns of this table reference. */
+ bool is_join_columns_complete;
+
+ /*
+ List of nodes in a nested join tree, that should be considered as
+ leaves with respect to name resolution. The leaves are: views,
+ top-most nodes representing NATURAL/USING joins, subqueries, and
+ base tables. All of these TABLE_LIST instances contain a
+ materialized list of columns. The list is local to a subquery.
+ */
+ struct st_table_list *next_name_resolution_table;
+ /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */
+ List<String> *use_index, *ignore_index;
+ TABLE *table; /* opened table */
/*
select_result for derived table to pass it from table creation to table
filling procedure
@@ -411,6 +516,10 @@ typedef struct st_table_list
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;
+ /*
+ True when the view field translation table is used to convert
+ schema table fields for backwards compatibility with SHOW command.
+ */
bool schema_table_reformed;
TMP_TABLE_PARAM *schema_table_param;
/* link to select_lex where this table was used */
@@ -423,7 +532,11 @@ typedef struct st_table_list
st_table_list *ancestor;
/* most upper view this table belongs to */
st_table_list *belong_to_view;
- /* list of join table tree leaves */
+ /*
+ List of all base tables local to a subquery including all view
+ tables. Unlike 'next_local', this in this list views are *not*
+ leaves. Created in setup_tables() -> make_leaves_list().
+ */
st_table_list *next_leaf;
Item *where; /* VIEW WHERE clause condition */
Item *check_option; /* WITH CHECK OPTION condition */
@@ -464,6 +577,9 @@ typedef struct st_table_list
st_table_list *embedding; /* nested join containing the table */
List<struct st_table_list> *join_list;/* join list the table belongs to */
bool cacheable_table; /* stop PS caching */
+
+ /* used for proper partially successful DROP DATABASE binlogging */
+ bool was_dropped;
/* used in multi-upd/views privilege check */
bool table_in_first_from_clause;
bool skip_temporary; /* this table shouldn't be temporary */
@@ -493,6 +609,9 @@ typedef struct st_table_list
bool set_insert_values(MEM_ROOT *mem_root);
void hide_view_error(THD *thd);
st_table_list *find_underlying_table(TABLE *table);
+ st_table_list *first_leaf_for_name_resolution();
+ st_table_list *last_leaf_for_name_resolution();
+ bool is_leaf_for_name_resolution();
inline bool prepare_check_option(THD *thd)
{
bool res= FALSE;
@@ -514,6 +633,10 @@ private:
class Item;
+/*
+ Iterator over the fields of a generic table reference.
+*/
+
class Field_iterator: public Sql_alloc
{
public:
@@ -527,6 +650,11 @@ public:
};
+/*
+ Iterator over the fields of a base table, view with temporary
+ table, or subquery.
+*/
+
class Field_iterator_table: public Field_iterator
{
Field **ptr;
@@ -542,6 +670,8 @@ public:
};
+/* Iterator over the fields of a merge view. */
+
class Field_iterator_view: public Field_iterator
{
Field_translator *ptr, *array_end;
@@ -555,8 +685,70 @@ public:
Item *create_item(THD *thd);
Item **item_ptr() {return &ptr->item; }
Field *field() { return 0; }
-
inline Item *item() { return ptr->item; }
+ Field_translator *field_translator() { return ptr; }
+};
+
+
+/*
+ Field_iterator interface to the list of materialized fields of a
+ NATURAL/USING join.
+*/
+
+class Field_iterator_natural_join: public Field_iterator
+{
+ List_iterator_fast<Natural_join_column> *column_ref_it;
+ Natural_join_column *cur_column_ref;
+public:
+ Field_iterator_natural_join() :column_ref_it(NULL), cur_column_ref(NULL) {}
+ ~Field_iterator_natural_join() { delete column_ref_it; }
+ void set(TABLE_LIST *table);
+ void next();
+ bool end_of_fields() { return !cur_column_ref; }
+ const char *name() { return cur_column_ref->name(); }
+ Item *create_item(THD *thd) { return cur_column_ref->create_item(thd); }
+ Field *field() { return cur_column_ref->field(); }
+ Natural_join_column *column_ref() { return cur_column_ref; }
+};
+
+
+/*
+ Generic iterator over the fields of an arbitrary table reference.
+
+ DESCRIPTION
+ This class unifies the various ways of iterating over the columns
+ of a table reference depending on the type of SQL entity it
+ represents. If such an entity represents a nested table reference,
+ this iterator encapsulates the iteration over the columns of the
+ members of the table reference.
+
+ IMPLEMENTATION
+ The implementation assumes that all underlying NATURAL/USING table
+ references already contain their result columns and are linked into
+ the list TABLE_LIST::next_name_resolution_table.
+*/
+
+class Field_iterator_table_ref: public Field_iterator
+{
+ TABLE_LIST *table_ref, *first_leaf, *last_leaf;
+ Field_iterator_table table_field_it;
+ Field_iterator_view view_field_it;
+ Field_iterator_natural_join natural_join_it;
+ Field_iterator *field_it;
+ void set_field_iterator();
+public:
+ Field_iterator_table_ref() :field_it(NULL) {}
+ void set(TABLE_LIST *table);
+ void next();
+ bool end_of_fields()
+ { return (table_ref == last_leaf && field_it->end_of_fields()); }
+ const char *name() { return field_it->name(); }
+ const char *table_name();
+ const char *db_name();
+ GRANT_INFO *grant();
+ Item *create_item(THD *thd) { return field_it->create_item(thd); }
+ Field *field() { return field_it->field(); }
+ Natural_join_column *get_or_create_column_ref(THD *thd, bool *is_created);
};
diff --git a/storage/heap/hp_delete.c b/storage/heap/hp_delete.c
index 5287533ae0a..2d94418a1bf 100644
--- a/storage/heap/hp_delete.c
+++ b/storage/heap/hp_delete.c
@@ -80,7 +80,7 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
custom_arg.search_flag= SEARCH_SAME;
old_allocated= keyinfo->rb_tree.allocated;
res= tree_delete(&keyinfo->rb_tree, info->recbuf, &custom_arg);
- info->s->index_length+= (keyinfo->rb_tree.allocated-old_allocated);
+ info->s->index_length-= (old_allocated - keyinfo->rb_tree.allocated);
return res;
}
diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c
index cb398b4afab..5dbbca0b17d 100644
--- a/storage/innobase/btr/btr0pcur.c
+++ b/storage/innobase/btr/btr0pcur.c
@@ -210,7 +210,7 @@ btr_pcur_restore_position(
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t));
if (cursor->trx_if_known) {
- trx_print(stderr, cursor->trx_if_known);
+ trx_print(stderr, cursor->trx_if_known, 0);
}
ut_error;
diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c
index f705fee4275..7a4e92a672a 100644
--- a/storage/innobase/btr/btr0sea.c
+++ b/storage/innobase/btr/btr0sea.c
@@ -964,6 +964,13 @@ btr_search_drop_page_hash_index(
heap = NULL;
offsets = NULL;
+ if (block->index == NULL) {
+
+ mem_analyze_corruption((byte*)block);
+
+ ut_a(block->index != NULL);
+ }
+
while (!page_rec_is_supremum(rec)) {
/* FIXME: in a mixed tree, not all records may have enough
ordering fields: */
diff --git a/storage/innobase/include/read0read.h b/storage/innobase/include/read0read.h
index b5edcefb544..7a91248cf7f 100644
--- a/storage/innobase/include/read0read.h
+++ b/storage/innobase/include/read0read.h
@@ -136,6 +136,9 @@ struct cursor_view_struct{
/* Memory heap for the cursor view */
read_view_t* read_view;
/* Consistent read view of the cursor*/
+ ulint n_mysql_tables_in_use;
+ /* number of Innobase tables used in the
+ processing of this cursor */
};
#ifndef UNIV_NONINL
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 116ae7b6438..11347f430d4 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -94,6 +94,7 @@ extern ulint srv_max_dirty_pages_pct;
extern ulint srv_force_recovery;
extern ulong srv_thread_concurrency;
+extern ulong srv_commit_concurrency;
extern ulint srv_max_n_threads;
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index a3ef755348c..5dbf003594f 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -329,17 +329,20 @@ trx_commit_step(
/*============*/
/* out: query thread to run next, or NULL */
que_thr_t* thr); /* in: query thread */
+
/**************************************************************************
-Prints info about a transaction to the standard output. The caller must
-own the kernel mutex and must have called
-innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or
-InnoDB cannot meanwhile change the info printed here. */
+Prints info about a transaction to the given file. The caller must own the
+kernel mutex and must have called
+innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL
+or InnoDB cannot meanwhile change the info printed here. */
void
trx_print(
/*======*/
- FILE* f, /* in: output stream */
- trx_t* trx); /* in: transaction */
+ FILE* f, /* in: output stream */
+ trx_t* trx, /* in: transaction */
+ uint max_query_len); /* in: max query length to print, or 0 to
+ use the default max length */
#ifndef UNIV_HOTBACKUP
/**************************************************************************
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 132ac9e18c5..6849dcd9c51 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -244,7 +244,7 @@ contains the sum of the following flag and the locally stored len. */
#define UNIV_EXTERN_STORAGE_FIELD (UNIV_SQL_NULL - UNIV_PAGE_SIZE)
/* Some macros to improve branch prediction and reduce cache misses */
-#if defined(__GNUC__) && (__GNUC__ > 2)
+#if defined(__GNUC__) && (__GNUC__ > 2) && ! defined(__INTEL_COMPILER)
/* Tell the compiler that 'expr' probably evaluates to 'constant'. */
# define UNIV_EXPECT(expr,constant) __builtin_expect(expr, constant)
/* Tell the compiler that a pointer is likely to be NULL */
diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c
index 280c4871ee9..1f222d71d6a 100644
--- a/storage/innobase/lock/lock0lock.c
+++ b/storage/innobase/lock/lock0lock.c
@@ -3297,7 +3297,7 @@ lock_deadlock_recursive(
fputs("\n*** (1) TRANSACTION:\n", ef);
- trx_print(ef, wait_lock->trx);
+ trx_print(ef, wait_lock->trx, 3000);
fputs(
"*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef);
@@ -3310,7 +3310,7 @@ lock_deadlock_recursive(
fputs("*** (2) TRANSACTION:\n", ef);
- trx_print(ef, lock->trx);
+ trx_print(ef, lock->trx, 3000);
fputs("*** (2) HOLDS THE LOCK(S):\n", ef);
@@ -4207,7 +4207,7 @@ lock_print_info_all_transactions(
while (trx) {
if (trx->conc_state == TRX_NOT_STARTED) {
fputs("---", file);
- trx_print(file, trx);
+ trx_print(file, trx, 600);
}
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
@@ -4239,7 +4239,7 @@ loop:
if (nth_lock == 0) {
fputs("---", file);
- trx_print(file, trx);
+ trx_print(file, trx, 600);
if (trx->read_view) {
fprintf(file,
diff --git a/storage/innobase/read/read0read.c b/storage/innobase/read/read0read.c
index 334f9a8a85a..06349c1fd39 100644
--- a/storage/innobase/read/read0read.c
+++ b/storage/innobase/read/read0read.c
@@ -286,6 +286,11 @@ read_cursor_view_create_for_mysql(
curview = (cursor_view_t*) mem_heap_alloc(heap, sizeof(cursor_view_t));
curview->heap = heap;
+ /* Drop cursor tables from consideration when evaluating the need of
+ auto-commit */
+ curview->n_mysql_tables_in_use = cr_trx->n_mysql_tables_in_use;
+ cr_trx->n_mysql_tables_in_use = 0;
+
mutex_enter(&kernel_mutex);
curview->read_view = read_view_create_low(
@@ -305,11 +310,13 @@ read_cursor_view_create_for_mysql(
n = 0;
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
- /* No active transaction should be visible, not even cr_trx !*/
+ /* No active transaction should be visible, except cr_trx.
+ This is quick fix for a bug 12456 and needs to be fixed when
+ semi-consistent high-granularity read view is implemented. */
while (trx) {
- if (trx->conc_state == TRX_ACTIVE ||
- trx->conc_state == TRX_PREPARED) {
+ if (trx != cr_trx && (trx->conc_state == TRX_ACTIVE ||
+ trx->conc_state == TRX_PREPARED)) {
read_view_set_nth_trx_id(view, n, trx->id);
@@ -360,6 +367,10 @@ read_cursor_view_close_for_mysql(
ut_a(curview->read_view);
ut_a(curview->heap);
+ /* Add cursor's tables to the global count of active tables that
+ belong to this transaction */
+ trx->n_mysql_tables_in_use += curview->n_mysql_tables_in_use;
+
mutex_enter(&kernel_mutex);
read_view_close(curview->read_view);
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index bce775c25d6..75d8117a73e 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -602,7 +602,7 @@ row_ins_foreign_report_err(
rewind(ef);
ut_print_timestamp(ef);
fputs(" Transaction:\n", ef);
- trx_print(ef, trx);
+ trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
@@ -653,7 +653,7 @@ row_ins_foreign_report_add_err(
rewind(ef);
ut_print_timestamp(ef);
fputs(" Transaction:\n", ef);
- trx_print(ef, trx);
+ trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
@@ -1228,7 +1228,7 @@ run_again:
rewind(ef);
ut_print_timestamp(ef);
fputs(" Transaction:\n", ef);
- trx_print(ef, trx);
+ trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
index 15881cb8c5d..a77010d939b 100644
--- a/storage/innobase/row/row0sel.c
+++ b/storage/innobase/row/row0sel.c
@@ -2685,7 +2685,7 @@ row_sel_get_clust_rec_for_mysql(
"InnoDB: clust index record ", stderr);
rec_print(stderr, clust_rec, clust_index);
putc('\n', stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 600);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
@@ -3101,12 +3101,6 @@ row_search_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
- /* Restore a global read view back to a transaction. This
- forces MySQL always to set a cursor view before fetch from
- a cursor. */
-
- trx->read_view = trx->global_read_view;
-
return(DB_ERROR);
}
@@ -3130,12 +3124,17 @@ row_search_for_mysql(
be zero; in that case select_lock_type is set to LOCK_X in
::start_stmt. */
+/* August 19, 2005 by Heikki: temporarily disable this error print until the
+cursor lock count is done correctly. See bugs #12263 and #12456!
+
fputs(
"InnoDB: Error: MySQL is trying to perform a SELECT\n"
"InnoDB: but it has not locked any tables in ::external_lock()!\n",
stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 600);
fputc('\n', stderr);
+*/
+
}
/* fprintf(stderr, "Match mode %lu\n search tuple ", (ulong) match_mode);
@@ -3461,7 +3460,7 @@ shortcut_fails_too_big_rec:
fputs(
"InnoDB: Error: MySQL is trying to perform a consistent read\n"
"InnoDB: but the read view is not assigned!\n", stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 600);
fputc('\n', stderr);
ut_a(0);
}
@@ -4098,12 +4097,6 @@ normal_return:
}
func_exit:
- /* Restore a global read view back to a transaction. This
- forces MySQL always to set a cursor view before fetch from
- a cursor. */
-
- trx->read_view = trx->global_read_view;
-
trx->op_info = "";
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c
index 0225a9faec5..f906027033f 100644
--- a/storage/innobase/row/row0umod.c
+++ b/storage/innobase/row/row0umod.c
@@ -431,7 +431,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
"InnoDB: record ", stderr);
rec_print(stderr, btr_pcur_get_rec(&pcur), index);
putc('\n', stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 0);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
} else {
diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c
index 514fb6bd577..4f44dbeae67 100644
--- a/storage/innobase/row/row0upd.c
+++ b/storage/innobase/row/row0upd.c
@@ -1279,7 +1279,7 @@ row_upd_sec_index_entry(
rec_print(stderr, rec, index);
putc('\n', stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 0);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index dc85750f0be..c585536baee 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -261,6 +261,7 @@ Value 10 should be good if there are less than 4 processors + 4 disks in the
computer. Bigger computers need bigger values. */
ulong srv_thread_concurrency = SRV_CONCURRENCY_THRESHOLD;
+ulong srv_commit_concurrency = 0;
os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data
structures */
@@ -999,7 +1000,7 @@ retry:
fputs(
" InnoDB: Error: trying to declare trx to enter InnoDB, but\n"
"InnoDB: it already is declared.\n", stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 0);
putc('\n', stderr);
os_fast_mutex_unlock(&srv_conc_mutex);
diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
index ffe4ba08ee9..325b0a109cf 100644
--- a/storage/innobase/srv/srv0start.c
+++ b/storage/innobase/srv/srv0start.c
@@ -1054,7 +1054,8 @@ innobase_start_or_create_for_mysql(void)
fprintf(stderr,
"InnoDB: Error: You have specified innodb_buffer_pool_awe_mem_mb\n"
-"InnoDB: in my.cnf, but AWE can only be used in Windows 2000 and later.\n");
+"InnoDB: in my.cnf, but AWE can only be used in Windows 2000 and later.\n"
+"InnoDB: To use AWE, InnoDB must be compiled with __WIN2000__ defined.\n");
return(DB_ERROR);
}
diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
index 1681bed9af2..078befb81d2 100644
--- a/storage/innobase/trx/trx0trx.c
+++ b/storage/innobase/trx/trx0trx.c
@@ -30,8 +30,9 @@ Created 3/26/1996 Heikki Tuuri
copy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */
void innobase_mysql_print_thd(
- FILE* f,
- void* thd);
+ FILE* f,
+ void* thd,
+ uint max_query_len);
/* Dummy session used currently in MySQL interface */
sess_t* trx_dummy_sess = NULL;
@@ -262,7 +263,7 @@ trx_free(
fputs(
" InnoDB: Error: Freeing a trx which is declared to be processing\n"
"InnoDB: inside InnoDB.\n", stderr);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 600);
putc('\n', stderr);
}
@@ -277,7 +278,7 @@ trx_free(
(ulong)trx->n_mysql_tables_in_use,
(ulong)trx->mysql_n_tables_locked);
- trx_print(stderr, trx);
+ trx_print(stderr, trx, 600);
ut_print_buf(stderr, (byte*)trx, sizeof(trx_t));
}
@@ -1651,16 +1652,18 @@ trx_mark_sql_stat_end(
}
/**************************************************************************
-Prints info about a transaction to the standard output. The caller must
-own the kernel mutex and must have called
-innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL or
-InnoDB cannot meanwhile change the info printed here. */
+Prints info about a transaction to the given file. The caller must own the
+kernel mutex and must have called
+innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL
+or InnoDB cannot meanwhile change the info printed here. */
void
trx_print(
/*======*/
- FILE* f, /* in: output stream */
- trx_t* trx) /* in: transaction */
+ FILE* f, /* in: output stream */
+ trx_t* trx, /* in: transaction */
+ uint max_query_len) /* in: max query length to print, or 0 to
+ use the default max length */
{
ibool newline;
@@ -1755,7 +1758,7 @@ trx_print(
}
if (trx->mysql_thd != NULL) {
- innobase_mysql_print_thd(f, trx->mysql_thd);
+ innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
}
}
diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c
index 34c3fe138a3..078853bad19 100644
--- a/storage/myisam/ft_boolean_search.c
+++ b/storage/myisam/ft_boolean_search.c
@@ -249,6 +249,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
MI_INFO *info=ftb->info;
uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
byte *lastkey_buf=ftbw->word+ftbw->off;
+ LINT_INIT(off);
LINT_INIT(off);
if (ftbw->flags & FTB_FLAG_TRUNC)
diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c
index ba48cbf1b62..b3937ab9607 100644
--- a/storage/myisam/myisampack.c
+++ b/storage/myisam/myisampack.c
@@ -695,14 +695,22 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
else
error=my_rename(new_name,org_name,MYF(MY_WME));
if (!error)
+ {
VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
+ if (tmp_dir[0])
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
}
}
else
{
if (tmp_dir[0])
+ {
error=my_copy(new_name,org_name,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_COPYTIME));
+ if (!error)
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
else
error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
}
diff --git a/storage/ndb/include/kernel/AttributeDescriptor.hpp b/storage/ndb/include/kernel/AttributeDescriptor.hpp
index af28e777213..2fe7c9f0973 100644
--- a/storage/ndb/include/kernel/AttributeDescriptor.hpp
+++ b/storage/ndb/include/kernel/AttributeDescriptor.hpp
@@ -23,7 +23,8 @@ class AttributeDescriptor {
friend class Dbacc;
friend class Dbtup;
friend class Dbtux;
-
+ friend class SimulatedBlock;
+
private:
static void setType(Uint32 &, Uint32 type);
static void setSize(Uint32 &, Uint32 size);
diff --git a/storage/ndb/include/kernel/BlockNumbers.h b/storage/ndb/include/kernel/BlockNumbers.h
index cb3cc697eee..49b5842ac4e 100644
--- a/storage/ndb/include/kernel/BlockNumbers.h
+++ b/storage/ndb/include/kernel/BlockNumbers.h
@@ -44,8 +44,7 @@
#define TRIX 0xFF
#define DBUTIL 0x100
#define SUMA 0x101
-#define GREP 0x102
-#define DBTUX 0x103
+#define DBTUX 0x102
const BlockReference BACKUP_REF = numberToRef(BACKUP, 0);
const BlockReference DBTC_REF = numberToRef(DBTC, 0);
@@ -61,7 +60,6 @@ const BlockReference CMVMI_REF = numberToRef(CMVMI, 0);
const BlockReference TRIX_REF = numberToRef(TRIX, 0);
const BlockReference DBUTIL_REF = numberToRef(DBUTIL, 0);
const BlockReference SUMA_REF = numberToRef(SUMA, 0);
-const BlockReference GREP_REF = numberToRef(GREP, 0);
const BlockReference DBTUX_REF = numberToRef(DBTUX, 0);
const BlockNumber MIN_BLOCK_NO = BACKUP;
diff --git a/storage/ndb/include/kernel/GlobalSignalNumbers.h b/storage/ndb/include/kernel/GlobalSignalNumbers.h
index cc016b1f3e5..adaa33b09d8 100644
--- a/storage/ndb/include/kernel/GlobalSignalNumbers.h
+++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h
@@ -777,8 +777,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES;
/**
* Grep signals
*/
-#define GSN_GREP_SUB_CREATE_REQ 606
-#define GSN_GREP_SUB_CREATE_REF 607
+#define GSN_ALTER_TABLE_REP 606
+#define GSN_API_BROADCAST_REP 607
#define GSN_GREP_SUB_CREATE_CONF 608
#define GSN_GREP_CREATE_REQ 609
#define GSN_GREP_CREATE_REF 610
diff --git a/storage/ndb/include/kernel/kernel_types.h b/storage/ndb/include/kernel/kernel_types.h
index b176d20798c..e16e61471e7 100644
--- a/storage/ndb/include/kernel/kernel_types.h
+++ b/storage/ndb/include/kernel/kernel_types.h
@@ -36,6 +36,13 @@ enum Operation_t {
#endif
};
+inline
+Uint32
+table_version_major(Uint32 ver)
+{
+ return ver & 0x00FFFFFF;
+}
+
#endif
diff --git a/storage/ndb/include/kernel/signaldata/AlterTable.hpp b/storage/ndb/include/kernel/signaldata/AlterTable.hpp
index 173a9acf9ed..16c9eb204c9 100644
--- a/storage/ndb/include/kernel/signaldata/AlterTable.hpp
+++ b/storage/ndb/include/kernel/signaldata/AlterTable.hpp
@@ -129,7 +129,8 @@ public:
InvalidPrimaryKeySize = 739,
NullablePrimaryKey = 740,
UnsupportedChange = 741,
- BackupInProgress = 762
+ BackupInProgress = 762,
+ IncompatibleVersions = 763
};
private:
@@ -177,4 +178,26 @@ private:
Uint32 tableVersion;
};
+/**
+ * Inform API about change of table definition
+ */
+struct AlterTableRep
+{
+ friend bool printALTER_TABLE_REP(FILE*, const Uint32*, Uint32, Uint16);
+
+ STATIC_CONST( SignalLength = 3 );
+
+ enum Change_type
+ {
+ CT_ALTERED = 0x1,
+ CT_DROPPED = 0x2
+ };
+
+ Uint32 tableId;
+ Uint32 tableVersion;
+ Uint32 changeType;
+
+ SECTION( TABLE_NAME = 0 );
+};
+
#endif
diff --git a/storage/ndb/include/ndbapi/NdbDictionary.hpp b/storage/ndb/include/ndbapi/NdbDictionary.hpp
index f37d71e3481..870af671959 100644
--- a/storage/ndb/include/ndbapi/NdbDictionary.hpp
+++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp
@@ -78,9 +78,10 @@ public:
///< changes to take effect
Retrieved, ///< The object exist and has been read
///< into main memory from NDB Kernel
- Invalid ///< The object has been invalidated
+ Invalid, ///< The object has been invalidated
///< and should not be used
-
+ Altered ///< Table has been altered in NDB kernel
+ ///< but is still valid for usage
};
/**
diff --git a/storage/ndb/include/portlib/NdbTCP.h b/storage/ndb/include/portlib/NdbTCP.h
index 308a3833ffd..9ed5b5e7f96 100644
--- a/storage/ndb/include/portlib/NdbTCP.h
+++ b/storage/ndb/include/portlib/NdbTCP.h
@@ -95,6 +95,8 @@ int Ndb_getInAddr(struct in_addr * dst, const char *address);
int NDB_CLOSE_SOCKET(int fd);
#endif
+int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock);
+
#ifdef __cplusplus
}
#endif
diff --git a/storage/ndb/src/common/debugger/BlockNames.cpp b/storage/ndb/src/common/debugger/BlockNames.cpp
index 44650b84c5c..0c61b6327ef 100644
--- a/storage/ndb/src/common/debugger/BlockNames.cpp
+++ b/storage/ndb/src/common/debugger/BlockNames.cpp
@@ -32,7 +32,6 @@ const BlockName BlockNames[] = {
{ "BACKUP", BACKUP },
{ "DBUTIL", DBUTIL },
{ "SUMA", SUMA },
- { "GREP", GREP },
{ "DBTUX", DBTUX }
};
diff --git a/storage/ndb/src/common/logger/LogHandler.cpp b/storage/ndb/src/common/logger/LogHandler.cpp
index a9d4512112f..521bd346fd3 100644
--- a/storage/ndb/src/common/logger/LogHandler.cpp
+++ b/storage/ndb/src/common/logger/LogHandler.cpp
@@ -58,7 +58,7 @@ LogHandler::append(const char* pCategory, Logger::LoggerLevel level,
}
else // repeated message
{
- if (now < m_last_log_time+m_max_repeat_frequency)
+ if (now < (time_t) (m_last_log_time+m_max_repeat_frequency))
{
m_count_repeated_messages++;
m_now= now;
diff --git a/storage/ndb/src/common/portlib/NdbTCP.cpp b/storage/ndb/src/common/portlib/NdbTCP.cpp
index c7b9d33c5f6..768292ac7c0 100644
--- a/storage/ndb/src/common/portlib/NdbTCP.cpp
+++ b/storage/ndb/src/common/portlib/NdbTCP.cpp
@@ -83,3 +83,18 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) {
return -1;
}
#endif
+
+int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock)
+{
+ struct pollfd pfd[1];
+ int r;
+
+ pfd[0].fd= sock;
+ pfd[0].events= POLLHUP | POLLIN | POLLOUT | POLLNVAL;
+ pfd[0].revents= 0;
+ r= poll(pfd,1,0);
+ if(pfd[0].revents & (POLLHUP|POLLERR))
+ return 1;
+
+ return 0;
+}
diff --git a/storage/ndb/src/common/portlib/win32/NdbTCP.c b/storage/ndb/src/common/portlib/win32/NdbTCP.c
index b936cd2db6c..a14cd4409eb 100644
--- a/storage/ndb/src/common/portlib/win32/NdbTCP.c
+++ b/storage/ndb/src/common/portlib/win32/NdbTCP.c
@@ -37,3 +37,35 @@ Ndb_getInAddr(struct in_addr * dst, const char *address)
return -1;
}
+int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock)
+{
+ fd_set readfds, writefds, errorfds;
+ struct timeval tv= {0,0};
+ int s_err;
+ int s_err_size= sizeof(s_err);
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&errorfds);
+
+ FD_SET(sock, &readfds);
+ FD_SET(sock, &writefds);
+ FD_SET(sock, &errorfds);
+
+ if(select(1, &readfds, &writefds, &errorfds, &t)==SOCKET_ERROR)
+ return 1;
+
+ if(FD_ISSET(sock,&errorfds))
+ return 1;
+
+ s_err=0;
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+ return(1);
+
+ if (s_err)
+ { /* getsockopt could succeed */
+ return(1); /* but return an error... */
+ }
+
+ return 0;
+}
diff --git a/storage/ndb/src/common/transporter/TransporterRegistry.cpp b/storage/ndb/src/common/transporter/TransporterRegistry.cpp
index 05cf9cdf16f..23ab799094f 100644
--- a/storage/ndb/src/common/transporter/TransporterRegistry.cpp
+++ b/storage/ndb/src/common/transporter/TransporterRegistry.cpp
@@ -1311,11 +1311,17 @@ TransporterRegistry::start_clients_thread()
if (server_port)
t->set_s_port(server_port);
}
- else
+ else if(ndb_mgm_is_connected(m_mgm_handle))
{
ndbout_c("Failed to get dynamic port to connect to: %d", res);
ndb_mgm_disconnect(m_mgm_handle);
}
+ else
+ {
+ ndbout_c("Management server closed connection early. "
+ "It is probably being shut down (or has crashed). "
+ "We will retry the connection.");
+ }
}
/** else
* We will not be able to get a new port unless
diff --git a/storage/ndb/src/common/util/version.c b/storage/ndb/src/common/util/version.c
index e87a342d7b1..e1ff204e91b 100644
--- a/storage/ndb/src/common/util/version.c
+++ b/storage/ndb/src/common/util/version.c
@@ -93,9 +93,10 @@ void ndbSetOwnVersion() {}
#ifndef TEST_VERSION
struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
{ MAKE_VERSION(5,1,NDB_VERSION_BUILD), MAKE_VERSION(5,1,0), UG_Range},
- { MAKE_VERSION(5,0,8), MAKE_VERSION(5,0,3), UG_Range},
- { MAKE_VERSION(5,0,3), MAKE_VERSION(5,0,2), UG_Exact },
- { MAKE_VERSION(4,1,12), MAKE_VERSION(4,1,10), UG_Range },
+ { MAKE_VERSION(5,0,NDB_VERSION_BUILD), MAKE_VERSION(5,0,12), UG_Range},
+ { MAKE_VERSION(5,0,11), MAKE_VERSION(5,0,2), UG_Range},
+ { MAKE_VERSION(4,1,NDB_VERSION_BUILD), MAKE_VERSION(4,1,15), UG_Range },
+ { MAKE_VERSION(4,1,14), MAKE_VERSION(4,1,10), UG_Range },
{ MAKE_VERSION(4,1,10), MAKE_VERSION(4,1,9), UG_Exact },
{ MAKE_VERSION(4,1,9), MAKE_VERSION(4,1,8), UG_Exact },
{ MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact },
@@ -103,7 +104,9 @@ struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
};
struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = {
+ { MAKE_VERSION(5,0,12), MAKE_VERSION(5,0,11), UG_Exact },
{ MAKE_VERSION(5,0,2), MAKE_VERSION(4,1,8), UG_Exact },
+ { MAKE_VERSION(4,1,15), MAKE_VERSION(4,1,14), UG_Exact },
{ MAKE_VERSION(3,5,4), MAKE_VERSION(3,5,3), UG_Exact },
{ 0, 0, UG_Null }
};
diff --git a/storage/ndb/src/kernel/Makefile.am b/storage/ndb/src/kernel/Makefile.am
index 6e3664f0997..9f8331ecf81 100644
--- a/storage/ndb/src/kernel/Makefile.am
+++ b/storage/ndb/src/kernel/Makefile.am
@@ -23,7 +23,6 @@ INCLUDES += \
-Iblocks/backup \
-Iblocks/dbutil \
-Iblocks/suma \
- -Iblocks/grep \
-Iblocks/dbtux
LDADD += \
@@ -41,7 +40,6 @@ LDADD += \
blocks/backup/libbackup.a \
blocks/dbutil/libdbutil.a \
blocks/suma/libsuma.a \
- blocks/grep/libgrep.a \
blocks/dbtux/libdbtux.a \
vm/libkernel.a \
error/liberror.a \
diff --git a/storage/ndb/src/kernel/SimBlockList.cpp b/storage/ndb/src/kernel/SimBlockList.cpp
index bf3958cf137..6029fc7e225 100644
--- a/storage/ndb/src/kernel/SimBlockList.cpp
+++ b/storage/ndb/src/kernel/SimBlockList.cpp
@@ -30,7 +30,6 @@
#include <Backup.hpp>
#include <DbUtil.hpp>
#include <Suma.hpp>
-#include <Grep.hpp>
#include <Dbtux.hpp>
#include <NdbEnv.h>
@@ -97,13 +96,14 @@ SimBlockList::load(const Configuration & conf){
theList[11] = NEW_BLOCK(Backup)(conf);
theList[12] = NEW_BLOCK(DbUtil)(conf);
theList[13] = NEW_BLOCK(Suma)(conf);
- theList[14] = NEW_BLOCK(Grep)(conf);
+ theList[14] = 0; //NEW_BLOCK(Grep)(conf);
theList[15] = NEW_BLOCK(Dbtux)(conf);
// Metadata common part shared by block instances
ptrMetaDataCommon = new MetaData::Common(*dbdict, *dbdih);
for (int i = 0; i < noOfBlocks; i++)
- theList[i]->setMetaDataCommon(ptrMetaDataCommon);
+ if(theList[i])
+ theList[i]->setMetaDataCommon(ptrMetaDataCommon);
}
void
diff --git a/storage/ndb/src/kernel/blocks/Makefile.am b/storage/ndb/src/kernel/blocks/Makefile.am
index 7ee90e6239f..8addf257003 100644
--- a/storage/ndb/src/kernel/blocks/Makefile.am
+++ b/storage/ndb/src/kernel/blocks/Makefile.am
@@ -13,7 +13,6 @@ SUBDIRS = \
backup \
dbutil \
suma \
- grep \
dbtux
windoze-dsp:
diff --git a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
index c313abc28eb..6f6aee6a7f7 100644
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
@@ -988,7 +988,6 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal)
sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
sendSignal(DBUTIL_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
sendSignal(SUMA_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
- sendSignal(GREP_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
sendSignal(TRIX_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
sendSignal(DBTUX_REF, GSN_DUMP_STATE_ORD, signal, signal->length(), JBB);
diff --git a/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
index aa1056e5570..8d9c9bda892 100644
--- a/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
+++ b/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
@@ -851,13 +851,6 @@ struct Tabrec {
Uint32 fragptrholder[MAX_FRAG_PER_NODE];
Uint32 tabUserPtr;
BlockReference tabUserRef;
-
- Uint8 noOfKeyAttr;
- Uint8 hasCharAttr;
- struct KeyAttr {
- Uint32 attributeDescriptor;
- CHARSET_INFO* charsetInfo;
- } keyAttr[MAX_ATTRIBUTES_IN_INDEX];
};
typedef Ptr<Tabrec> TabrecPtr;
@@ -903,7 +896,6 @@ private:
void execACCKEYREQ(Signal* signal);
void execACCSEIZEREQ(Signal* signal);
void execACCFRAGREQ(Signal* signal);
- void execTC_SCHVERREQ(Signal* signal);
void execACC_SRREQ(Signal* signal);
void execNEXT_SCANREQ(Signal* signal);
void execACC_ABORTREQ(Signal* signal);
diff --git a/storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp b/storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
index ccc65ccf9fa..e735e3a372f 100644
--- a/storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
+++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
@@ -179,7 +179,6 @@ Dbacc::Dbacc(const class Configuration & conf):
addRecSignal(GSN_ACCKEYREQ, &Dbacc::execACCKEYREQ);
addRecSignal(GSN_ACCSEIZEREQ, &Dbacc::execACCSEIZEREQ);
addRecSignal(GSN_ACCFRAGREQ, &Dbacc::execACCFRAGREQ);
- addRecSignal(GSN_TC_SCHVERREQ, &Dbacc::execTC_SCHVERREQ);
addRecSignal(GSN_ACC_SRREQ, &Dbacc::execACC_SRREQ);
addRecSignal(GSN_NEXT_SCANREQ, &Dbacc::execNEXT_SCANREQ);
addRecSignal(GSN_ACC_ABORTREQ, &Dbacc::execACC_ABORTREQ);
diff --git a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
index 1a49e95d28c..1f070127936 100644
--- a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
@@ -28,7 +28,8 @@
#include <signaldata/FsRemoveReq.hpp>
#include <signaldata/DropTab.hpp>
#include <signaldata/DumpStateOrd.hpp>
-#include <SectionReader.hpp>
+#include <KeyDescriptor.hpp>
+
// TO_DO_RONM is a label for comments on what needs to be improved in future versions
// when more time is given.
@@ -1037,12 +1038,6 @@ void Dbacc::initialiseTableRec(Signal* signal)
tabptr.p->fragholder[i] = RNIL;
tabptr.p->fragptrholder[i] = RNIL;
}//for
- tabptr.p->noOfKeyAttr = 0;
- tabptr.p->hasCharAttr = 0;
- for (Uint32 k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) {
- tabptr.p->keyAttr[k].attributeDescriptor = 0;
- tabptr.p->keyAttr[k].charsetInfo = 0;
- }
}//for
}//Dbacc::initialiseTableRec()
@@ -1172,8 +1167,8 @@ void Dbacc::execACCFRAGREQ(Signal* signal)
Uint32 userPtr = req->userPtr;
BlockReference retRef = req->userRef;
rootfragrecptr.p->rootState = ACTIVEROOT;
- AccFragConf * const conf = (AccFragConf*)&signal->theData[0];
+ AccFragConf * const conf = (AccFragConf*)&signal->theData[0];
conf->userPtr = userPtr;
conf->rootFragPtr = rootfragrecptr.i;
conf->fragId[0] = rootfragrecptr.p->fragmentid[0];
@@ -1197,65 +1192,6 @@ void Dbacc::addFragRefuse(Signal* signal, Uint32 errorCode)
return;
}//Dbacc::addFragRefuseEarly()
-void
-Dbacc::execTC_SCHVERREQ(Signal* signal)
-{
- jamEntry();
- if (! assembleFragments(signal)) {
- jam();
- return;
- }
- tabptr.i = signal->theData[0];
- ptrCheckGuard(tabptr, ctablesize, tabrec);
- Uint32 noOfKeyAttr = signal->theData[6];
- ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
- Uint32 hasCharAttr = 0;
-
- SegmentedSectionPtr s0Ptr;
- signal->getSection(s0Ptr, 0);
- SectionReader r0(s0Ptr, getSectionSegmentPool());
- Uint32 i = 0;
- while (i < noOfKeyAttr) {
- jam();
- Uint32 attributeDescriptor = ~0;
- Uint32 csNumber = ~0;
- if (! r0.getWord(&attributeDescriptor) ||
- ! r0.getWord(&csNumber)) {
- jam();
- break;
- }
- CHARSET_INFO* cs = 0;
- if (csNumber != 0) {
- cs = all_charsets[csNumber];
- ndbrequire(cs != 0);
- hasCharAttr = 1;
- }
- tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor;
- tabptr.p->keyAttr[i].charsetInfo = cs;
- i++;
- }
- ndbrequire(i == noOfKeyAttr);
- releaseSections(signal);
-
- tabptr.p->noOfKeyAttr = noOfKeyAttr;
- tabptr.p->hasCharAttr = hasCharAttr;
-
- // copy char attr flag to each fragment
- for (Uint32 i1 = 0; i1 < MAX_FRAG_PER_NODE; i1++) {
- jam();
- if (tabptr.p->fragptrholder[i1] != RNIL) {
- rootfragrecptr.i = tabptr.p->fragptrholder[i1];
- ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
- for (Uint32 i2 = 0; i2 < 2; i2++) {
- fragrecptr.i = rootfragrecptr.p->fragmentptr[i2];
- ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
- fragrecptr.p->hasCharAttr = hasCharAttr;
- }
- }
- }
-
- // no reply to DICT
-}
void
Dbacc::execDROP_TAB_REQ(Signal* signal){
@@ -1841,55 +1777,14 @@ void Dbacc::execACCKEYREQ(Signal* signal)
void
Dbacc::xfrmKeyData(Signal* signal)
{
- tabptr.i = fragrecptr.p->myTableId;
- ptrCheckGuard(tabptr, ctablesize, tabrec);
-
- Uint32 dst[1024 * MAX_XFRM_MULTIPLY];
- Uint32 dstSize = (sizeof(dst) >> 2);
+ Uint32 table = fragrecptr.p->myTableId;
+ Uint32 dst[MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY];
+ Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
Uint32* src = &signal->theData[7];
- const Uint32 noOfKeyAttr = tabptr.p->noOfKeyAttr;
- Uint32 dstPos = 0;
- Uint32 srcPos = 0;
- Uint32 i = 0;
-
- while (i < noOfKeyAttr) {
- const Tabrec::KeyAttr& keyAttr = tabptr.p->keyAttr[i];
-
- Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
- Uint32 srcWords = (srcBytes + 3) / 4;
- Uint32 dstWords = ~0;
- uchar* dstPtr = (uchar*)&dst[dstPos];
- const uchar* srcPtr = (const uchar*)&src[srcPos];
- CHARSET_INFO* cs = keyAttr.charsetInfo;
-
- if (cs == 0) {
- jam();
- memcpy(dstPtr, srcPtr, srcWords << 2);
- dstWords = srcWords;
- } else {
- jam();
- Uint32 typeId = AttributeDescriptor::getType(keyAttr.attributeDescriptor);
- Uint32 lb, len;
- bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
- ndbrequire(ok);
- Uint32 xmul = cs->strxfrm_multiply;
- if (xmul == 0)
- xmul = 1;
- // see comment in DbtcMain.cpp
- Uint32 dstLen = xmul * (srcBytes - lb);
- ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
- int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
- ndbrequire(n != -1);
- while ((n & 3) != 0)
- dstPtr[n++] = 0;
- dstWords = (n >> 2);
- }
- dstPos += dstWords;
- srcPos += srcWords;
- i++;
- }
- memcpy(src, dst, dstPos << 2);
- operationRecPtr.p->xfrmtupkeylen = dstPos;
+ Uint32 len = xfrm_key(table, src, dst, sizeof(dst) >> 2, keyPartLen);
+ ndbrequire(len); // 0 means error
+ memcpy(src, dst, len << 2);
+ operationRecPtr.p->xfrmtupkeylen = len;
}
void Dbacc::accIsLockedLab(Signal* signal)
@@ -8024,6 +7919,10 @@ void Dbacc::initFragAdd(Signal* signal,
Uint32 Tmp2 = regFragPtr.p->maxloadfactor - regFragPtr.p->minloadfactor;
Tmp2 = Tmp1 * Tmp2;
regFragPtr.p->slackCheck = Tmp2;
+
+ Uint32 hasCharAttr = g_key_descriptor_pool.getPtr(req->tableId)->hasCharAttr;
+ regFragPtr.p->hasCharAttr = hasCharAttr;
+
}//Dbacc::initFragAdd()
void Dbacc::initFragGeneral(FragmentrecPtr regFragPtr)
diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
index 3b1fddef00e..0a33966ef73 100644
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
@@ -27,6 +27,7 @@
#include <SectionReader.hpp>
#include <SimpleProperties.hpp>
#include <AttributeHeader.hpp>
+#include <KeyDescriptor.hpp>
#include <signaldata/DictSchemaInfo.hpp>
#include <signaldata/DictTabInfo.hpp>
#include <signaldata/DropTabFile.hpp>
@@ -77,6 +78,7 @@
#include <signaldata/CreateFragmentation.hpp>
#include <signaldata/CreateTab.hpp>
#include <NdbSleep.h>
+#include <signaldata/ApiBroadcast.hpp>
#define ZNOT_FOUND 626
#define ZALREADYEXIST 630
@@ -91,6 +93,27 @@
#define DIV(x,y) (((x)+(y)-1)/(y))
#include <ndb_version.h>
+static
+Uint32
+alter_table_inc_schema_version(Uint32 old)
+{
+ return (old & 0x00FFFFFF) + ((old + 0x1000000) & 0xFF000000);
+}
+
+static
+Uint32
+alter_table_dec_schema_version(Uint32 old)
+{
+ return (old & 0x00FFFFFF) + ((old - 0x1000000) & 0xFF000000);
+}
+
+static
+Uint32
+create_table_inc_schema_version(Uint32 old)
+{
+ return (old + 0x00000001) & 0x00FFFFFF;
+}
+
/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE: GENERAL MODULE -------------------------------- */
@@ -603,7 +626,7 @@ void Dbdict::openTableFile(Signal* signal,
jam();
fsOpenReq->fileFlags = FsOpenReq::OM_READONLY;
}//if
- ndbrequire(tablePtr.p->tableVersion < ZNIL);
+
fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes
FsOpenReq::setVersion(fsOpenReq->fileNumber, 1);
FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_TABLELIST);
@@ -793,7 +816,7 @@ Dbdict::updateSchemaState(Signal* signal, Uint32 tableId,
case SchemaFile::ADD_STARTED:
jam();
ok = true;
- ndbrequire((oldVersion + 1) == newVersion);
+ ndbrequire(create_table_inc_schema_version(oldVersion) == newVersion);
ndbrequire(oldState == SchemaFile::INIT ||
oldState == SchemaFile::DROP_TABLE_COMMITTED);
break;
@@ -806,7 +829,7 @@ Dbdict::updateSchemaState(Signal* signal, Uint32 tableId,
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
ok = true;
- ndbrequire((oldVersion + 1) == newVersion);
+ ndbrequire(alter_table_inc_schema_version(oldVersion) == newVersion);
ndbrequire(oldState == SchemaFile::TABLE_ADD_COMMITTED ||
oldState == SchemaFile::ALTER_TABLE_COMMITTED);
break;
@@ -1730,6 +1753,7 @@ void Dbdict::execREAD_CONFIG_REQ(Signal* signal)
c_schemaPageRecordArray.setSize(2 * NDB_SF_MAX_PAGES);
c_tableRecordPool.setSize(tablerecSize);
c_tableRecordHash.setSize(tablerecSize);
+ g_key_descriptor_pool.setSize(tablerecSize);
c_triggerRecordPool.setSize(c_maxNoOfTriggers);
c_triggerRecordHash.setSize(c_maxNoOfTriggers);
c_opRecordPool.setSize(256); // XXX need config params
@@ -3014,6 +3038,21 @@ Dbdict::execBACKUP_FRAGMENT_REQ(Signal* signal)
}
}
+bool
+Dbdict::check_ndb_versions() const
+{
+ Uint32 node = 0;
+ Uint32 version = getNodeInfo(getOwnNodeId()).m_version;
+ while((node = c_aliveNodes.find(node + 1)) != BitmaskImpl::NotFound)
+ {
+ if(getNodeInfo(node).m_version != version)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
void
Dbdict::execALTER_TABLE_REQ(Signal* signal)
{
@@ -3050,6 +3089,13 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal)
alterTableRef(signal, req, AlterTableRef::Busy);
return;
}
+
+ if (!check_ndb_versions())
+ {
+ jam();
+ alterTableRef(signal, req, AlterTableRef::IncompatibleVersions);
+ return;
+ }
const TableRecord::TabState tabState = tablePtr.p->tabState;
bool ok = false;
@@ -3200,7 +3246,7 @@ Dbdict::alterTable_backup_mutex_locked(Signal* signal,
lreq->clientData = alterTabPtr.p->m_senderData;
lreq->changeMask = alterTabPtr.p->m_changeMask;
lreq->tableId = tablePtr.p->tableId;
- lreq->tableVersion = tablePtr.p->tableVersion + 1;
+ lreq->tableVersion = alter_table_inc_schema_version(tablePtr.p->tableVersion);
lreq->gci = tablePtr.p->gciTableCreated;
lreq->requestType = AlterTabReq::AlterTablePrepare;
@@ -3280,6 +3326,14 @@ Dbdict::execALTER_TAB_REQ(Signal * signal)
alterTabRef(signal, req, AlterTableRef::Busy);
return;
}
+
+ if (!check_ndb_versions())
+ {
+ jam();
+ alterTabRef(signal, req, AlterTableRef::IncompatibleVersions);
+ return;
+ }
+
alterTabPtr.p->m_alterTableId = tableId;
alterTabPtr.p->m_coordinatorRef = senderRef;
@@ -3322,7 +3376,7 @@ Dbdict::execALTER_TAB_REQ(Signal * signal)
}
ndbrequire(ok);
- if(tablePtr.p->tableVersion + 1 != tableVersion){
+ if(alter_table_inc_schema_version(tablePtr.p->tableVersion) != tableVersion){
jam();
alterTabRef(signal, req, AlterTableRef::InvalidTableVersion);
return;
@@ -3807,7 +3861,7 @@ void Dbdict::revertAlterTable(Signal * signal,
// Restore name
strcpy(tablePtr.p->tableName, alterTabPtrP->previousTableName);
// Revert schema version
- tablePtr.p->tableVersion = tablePtr.p->tableVersion - 1;
+ tablePtr.p->tableVersion = alter_table_dec_schema_version(tablePtr.p->tableVersion);
// Put it back
#ifdef VM_TRACE
ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p));
@@ -3867,6 +3921,27 @@ Dbdict::alterTab_writeTableConf(Signal* signal,
conf->requestType = AlterTabReq::AlterTableCommit;
sendSignal(coordinatorRef, GSN_ALTER_TAB_CONF, signal,
AlterTabConf::SignalLength, JBB);
+
+
+ {
+ ApiBroadcastRep* api= (ApiBroadcastRep*)signal->getDataPtrSend();
+ api->gsn = GSN_ALTER_TABLE_REP;
+ api->minVersion = MAKE_VERSION(4,1,15);
+
+ AlterTableRep* rep = (AlterTableRep*)api->theData;
+ rep->tableId = tabPtr.p->tableId;
+ rep->tableVersion = alter_table_dec_schema_version(tabPtr.p->tableVersion);
+ rep->changeType = AlterTableRep::CT_ALTERED;
+
+ LinearSectionPtr ptr[3];
+ ptr[0].p = (Uint32*)alterTabPtr.p->previousTableName;
+ ptr[0].sz = (sizeof(alterTabPtr.p->previousTableName) + 3) >> 2;
+
+ sendSignal(QMGR_REF, GSN_API_BROADCAST_REP, signal,
+ ApiBroadcastRep::SignalLength + AlterTableRep::SignalLength,
+ JBB, ptr,1);
+ }
+
if(coordinatorRef != reference()) {
jam();
// Release resources
@@ -3918,7 +3993,7 @@ Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){
XSchemaFile * xsf = &c_schemaFile[c_schemaRecord.schemaPage != 0];
SchemaFile::TableEntry * tabEntry = getTableEntry(xsf, tabPtr.i);
- tabPtr.p->tableVersion = tabEntry->m_tableVersion + 1;
+ tabPtr.p->tableVersion = create_table_inc_schema_version(tabEntry->m_tableVersion);
/**
* Pack
@@ -3947,7 +4022,7 @@ Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){
req->gci = 0;
req->tableId = tabPtr.i;
- req->tableVersion = tabEntry->m_tableVersion + 1;
+ req->tableVersion = create_table_inc_schema_version(tabEntry->m_tableVersion);
sendFragmentedSignal(rg, GSN_CREATE_TAB_REQ, signal,
CreateTabReq::SignalLength, JBB);
@@ -4409,6 +4484,44 @@ Dbdict::execADD_FRAGREQ(Signal* signal) {
sendSignal(DBLQH_REF, GSN_LQHFRAGREQ, signal,
LqhFragReq::SignalLength, JBB);
}
+
+ /**
+ * Create KeyDescriptor
+ */
+ KeyDescriptor* desc= g_key_descriptor_pool.getPtr(tabPtr.i);
+ new (desc) KeyDescriptor();
+
+ Uint32 key = 0;
+ Uint32 tAttr = tabPtr.p->firstAttribute;
+ while (tAttr != RNIL)
+ {
+ jam();
+ AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
+ if (aRec->tupleKey)
+ {
+ desc->noOfKeyAttr ++;
+ desc->keyAttr[key].attributeDescriptor = aRec->attributeDescriptor;
+
+ Uint32 csNumber = (aRec->extPrecision >> 16);
+ if(csNumber)
+ {
+ desc->keyAttr[key].charsetInfo = all_charsets[csNumber];
+ ndbrequire(all_charsets[csNumber]);
+ desc->hasCharAttr = 1;
+ }
+ else
+ {
+ desc->keyAttr[key].charsetInfo = 0;
+ }
+ if(AttributeDescriptor::getDKey(aRec->attributeDescriptor))
+ {
+ desc->noOfDistrKeys ++;
+ }
+ key++;
+ }
+ tAttr = aRec->nextAttrInTable;
+ }
+ ndbrequire(key == tabPtr.p->noOfPrimkey);
}
void
@@ -4603,31 +4716,11 @@ Dbdict::execTAB_COMMITCONF(Signal* signal){
signal->theData[4] = (Uint32)tabPtr.p->tableType;
signal->theData[5] = createTabPtr.p->key;
signal->theData[6] = (Uint32)tabPtr.p->noOfPrimkey;
-
- Uint32 buf[2 * MAX_ATTRIBUTES_IN_INDEX];
- Uint32 sz = 0;
- Uint32 tAttr = tabPtr.p->firstAttribute;
- while (tAttr != RNIL) {
- jam();
- AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
- if (aRec->tupleKey) {
- buf[sz++] = aRec->attributeDescriptor;
- buf[sz++] = (aRec->extPrecision >> 16); // charset number
- }
- tAttr = aRec->nextAttrInTable;
- }
- ndbrequire((int)sz == 2 * tabPtr.p->noOfPrimkey);
-
- LinearSectionPtr lsPtr[3];
- lsPtr[0].p = buf;
- lsPtr[0].sz = sz;
- // note: ACC does not reply
- if (tabPtr.p->isTable() || tabPtr.p->isHashIndex())
- sendSignal(DBACC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
- sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
+
+ sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB);
return;
}
-
+
ndbrequire(false);
}
@@ -12312,3 +12405,5 @@ Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table
new (&attr) MetaData::Attribute(*attrPtr.p);
return 0;
}
+
+CArray<KeyDescriptor> g_key_descriptor_pool;
diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
index 45f43e5ad78..b7f6fe03eb1 100644
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
@@ -591,6 +591,7 @@ private:
void execALTER_TAB_REQ(Signal* signal);
void execALTER_TAB_REF(Signal* signal);
void execALTER_TAB_CONF(Signal* signal);
+ bool check_ndb_versions() const;
/*
* 2.4 COMMON STORED VARIABLES
diff --git a/storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp b/storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp
index b9b144cd977..9858744a61d 100644
--- a/storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp
+++ b/storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp
@@ -85,7 +85,8 @@ print_old(const char * filename, const SchemaFile * sf)
te.m_tableState != SchemaFile::DROP_TABLE_COMMITTED)) {
ndbout << "Table " << i << ":"
<< " State = " << te.m_tableState
- << " version = " << te.m_tableVersion
+ << " version = " << table_version_major(te.m_tableVersion) <<
+ << "(" << table_version_minor(te.m_tableVersion) << ")"
<< " type = " << te.m_tableType
<< " noOfPages = " << te.m_noOfPages
<< " gcp: " << te.m_gcp << endl;
diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index a22e2c28cd7..f6bec853a63 100644
--- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -1886,8 +1886,6 @@ void Dbdih::execINCL_NODECONF(Signal* signal)
// Suma will not send response to this for now, later...
sendSignal(SUMA_REF, GSN_INCL_NODEREQ, signal, 2, JBB);
- // Grep will not send response to this for now, later...
- sendSignal(GREP_REF, GSN_INCL_NODEREQ, signal, 2, JBB);
return;
}//if
if (TstartNode_or_blockref == numberToRef(BACKUP, getOwnNodeId())){
diff --git a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
index 5328f42ba83..95f510a5a60 100644
--- a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
+++ b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
@@ -2233,7 +2233,7 @@ private:
void LQHKEY_abort(Signal* signal, int errortype);
void LQHKEY_error(Signal* signal, int errortype);
void nextRecordCopy(Signal* signal);
- void calculateHash(Signal* signal);
+ Uint32 calculateHash(Uint32 tableId, const Uint32* src);
void continueAfterCheckLcpStopBlocked(Signal* signal);
void checkLcpStopBlockedLab(Signal* signal);
void sendCommittedTc(Signal* signal, BlockReference atcBlockref);
diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
index cb31b77221e..502fd91b87b 100644
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
@@ -55,6 +55,7 @@
#include <signaldata/AlterTab.hpp>
#include <signaldata/LCP.hpp>
+#include <KeyDescriptor.hpp>
// Use DEBUG to print messages that should be
// seen only when we debug the product
@@ -3522,7 +3523,8 @@ void Dblqh::execLQHKEYREQ(Signal* signal)
LQHKEY_abort(signal, 4);
return;
}
- if(tabptr.p->schemaVersion != schemaVersion){
+ if(table_version_major(tabptr.p->schemaVersion) !=
+ table_version_major(schemaVersion)){
LQHKEY_abort(signal, 5);
return;
}
@@ -4461,7 +4463,7 @@ void Dblqh::packLqhkeyreqLab(Signal* signal)
lqhKeyReq->requestInfo = Treqinfo;
lqhKeyReq->tcBlockref = sig4;
- sig0 = regTcPtr->tableref + (regTcPtr->schemaVersion << 16);
+ sig0 = regTcPtr->tableref + ((regTcPtr->schemaVersion << 16) & 0xFFFF0000);
sig1 = regTcPtr->fragmentid + (regTcPtr->nodeAfterNext[0] << 16);
sig2 = regTcPtr->transid[0];
sig3 = regTcPtr->transid[1];
@@ -9012,44 +9014,17 @@ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted)
/* FRAGMENT TO A NEW REPLICA OF THE FRAGMENT. IT DOES ALSO SHUT DOWN ALL */
/* CONNECTIONS TO THE FAILED NODE. */
/*---------------------------------------------------------------------------*/
-void Dblqh::calculateHash(Signal* signal)
-{
- DatabufPtr locDatabufptr;
- UintR Ti;
- UintR Tdata0;
- UintR Tdata1;
- UintR Tdata2;
- UintR Tdata3;
- UintR* Tdata32;
- Uint64 Tdata[512];
-
- Tdata32 = (UintR*)&Tdata[0];
-
- Tdata0 = tcConnectptr.p->tupkeyData[0];
- Tdata1 = tcConnectptr.p->tupkeyData[1];
- Tdata2 = tcConnectptr.p->tupkeyData[2];
- Tdata3 = tcConnectptr.p->tupkeyData[3];
- Tdata32[0] = Tdata0;
- Tdata32[1] = Tdata1;
- Tdata32[2] = Tdata2;
- Tdata32[3] = Tdata3;
- locDatabufptr.i = tcConnectptr.p->firstTupkeybuf;
- Ti = 4;
- while (locDatabufptr.i != RNIL) {
- ptrCheckGuard(locDatabufptr, cdatabufFileSize, databuf);
- Tdata0 = locDatabufptr.p->data[0];
- Tdata1 = locDatabufptr.p->data[1];
- Tdata2 = locDatabufptr.p->data[2];
- Tdata3 = locDatabufptr.p->data[3];
- Tdata32[Ti ] = Tdata0;
- Tdata32[Ti + 1] = Tdata1;
- Tdata32[Ti + 2] = Tdata2;
- Tdata32[Ti + 3] = Tdata3;
- locDatabufptr.i = locDatabufptr.p->nextDatabuf;
- Ti += 4;
- }//while
- tcConnectptr.p->hashValue =
- md5_hash((Uint64*)&Tdata32[0], (UintR)tcConnectptr.p->primKeyLen);
+Uint32
+Dblqh::calculateHash(Uint32 tableId, const Uint32* src)
+{
+ jam();
+ Uint64 Tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
+ Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
+ Uint32 keyLen = xfrm_key(tableId, src, (Uint32*)Tmp, sizeof(Tmp) >> 2,
+ keyPartLen);
+ ndbrequire(keyLen);
+
+ return md5_hash(Tmp, keyLen);
}//Dblqh::calculateHash()
/* *************************************** */
@@ -9383,7 +9358,7 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr();
UintR readLength = tupKeyConf->readLength;
-
+ Uint32 tableId = tcConnectptr.p->tableref;
scanptr.i = tcConnectptr.p->tcScanRec;
c_scanRecordPool.getPtr(scanptr);
ScanRecord* scanP = scanptr.p;
@@ -9410,7 +9385,14 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
Uint32 len= tcConnectptr.p->primKeyLen = readPrimaryKeys(scanP, tcConP, tmp);
// Calculate hash (no need to linearies key)
- tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len);
+ if (g_key_descriptor_pool.getPtr(tableId)->hasCharAttr)
+ {
+ tcConnectptr.p->hashValue = calculateHash(tableId, tmp);
+ }
+ else
+ {
+ tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len);
+ }
// Move into databuffer to make packLqhkeyreqLab happy
memcpy(tcConP->tupkeyData, tmp, 4*4);
@@ -15922,7 +15904,7 @@ Uint32 Dblqh::checkIfExecLog(Signal* signal)
tabptr.i = tcConnectptr.p->tableref;
ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
if (getFragmentrec(signal, tcConnectptr.p->fragmentid) &&
- (tabptr.p->schemaVersion == tcConnectptr.p->schemaVersion)) {
+ (table_version_major(tabptr.p->schemaVersion) == table_version_major(tcConnectptr.p->schemaVersion))) {
if (fragptr.p->execSrStatus != Fragrecord::IDLE) {
if (fragptr.p->execSrNoReplicas > logPartPtr.p->execSrExecuteIndex) {
ndbrequire((fragptr.p->execSrNoReplicas - 1) < 4);
diff --git a/storage/ndb/src/kernel/blocks/dblqh/Makefile.am b/storage/ndb/src/kernel/blocks/dblqh/Makefile.am
index 4807a8ec5d0..51cc12feb06 100644
--- a/storage/ndb/src/kernel/blocks/dblqh/Makefile.am
+++ b/storage/ndb/src/kernel/blocks/dblqh/Makefile.am
@@ -1,12 +1,16 @@
-#SUBDIRS = redoLogReader
-
noinst_LIBRARIES = libdblqh.a
+EXTRA_PROGRAMS = ndbd_redo_log_reader
libdblqh_a_SOURCES = DblqhInit.cpp DblqhMain.cpp
+ndbd_redo_log_reader_SOURCES = redoLogReader/records.cpp redoLogReader/redoLogFileReader.cpp
include $(top_srcdir)/storage/ndb/config/common.mk.am
include $(top_srcdir)/storage/ndb/config/type_kernel.mk.am
+LDADD += \
+ $(top_builddir)/storage/ndb/src/common/util/libgeneral.la \
+ $(top_builddir)/storage/ndb/src/common/portlib/libportlib.la
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile b/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile
deleted file mode 100644
index a89b648de77..00000000000
--- a/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include .defs.mk
-
-BIN_TARGET := redoLogFileReader
-
-SOURCES := records.cpp redoLogFileReader.cpp
-
-TYPE := util
-
-include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp
index 540df7b507e..67e59c48ea6 100644
--- a/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp
+++ b/storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp
@@ -40,7 +40,7 @@ Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords);
void readArguments(int argc, const char** argv);
void doExit();
-FILE * f;
+FILE * f= 0;
char fileName[256];
bool thePrintFlag = true;
bool theCheckFlag = true;
@@ -458,7 +458,7 @@ void readArguments(int argc, const char** argv)
void doExit() {
ndbout << "Error in redoLogReader(). Exiting!" << endl;
- fclose(f);
+ if (f) fclose(f);
delete [] redoLogPage;
exit(RETURN_ERROR);
}
diff --git a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
index 79b6cec6d44..c6d72135fc5 100644
--- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
+++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
@@ -969,13 +969,9 @@ public:
Uint8 hasCharAttr;
Uint8 noOfDistrKeys;
- struct KeyAttr {
- Uint32 attributeDescriptor;
- CHARSET_INFO* charsetInfo;
- } keyAttr[MAX_ATTRIBUTES_IN_INDEX];
-
bool checkTable(Uint32 schemaVersion) const {
- return enabled && !dropping && (schemaVersion == currentSchemaVersion);
+ return enabled && !dropping &&
+ (table_version_major(schemaVersion) == table_version_major(currentSchemaVersion));
}
Uint32 getErrorCode(Uint32 schemaVersion) const;
diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index f307f0576bf..8c32c87e05e 100644
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -66,6 +66,7 @@
#include <signaldata/DictTabInfo.hpp>
#include <AttributeDescriptor.hpp>
#include <SectionReader.hpp>
+#include <KeyDescriptor.hpp>
#include <NdbOut.hpp>
#include <DebuggerNames.hpp>
@@ -329,42 +330,16 @@ void Dbtc::execTC_SCHVERREQ(Signal* signal)
BlockReference retPtr = signal->theData[5];
Uint32 noOfKeyAttr = signal->theData[6];
ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
- Uint32 hasCharAttr = 0;
- Uint32 noOfDistrKeys = 0;
- SegmentedSectionPtr s0Ptr;
- signal->getSection(s0Ptr, 0);
- SectionReader r0(s0Ptr, getSectionSegmentPool());
- Uint32 i = 0;
- while (i < noOfKeyAttr) {
- jam();
- Uint32 attributeDescriptor = ~0;
- Uint32 csNumber = ~0;
- if (! r0.getWord(&attributeDescriptor) ||
- ! r0.getWord(&csNumber)) {
- jam();
- break;
- }
- CHARSET_INFO* cs = 0;
- if (csNumber != 0) {
- cs = all_charsets[csNumber];
- ndbrequire(cs != 0);
- hasCharAttr = 1;
- }
-
- noOfDistrKeys += AttributeDescriptor::getDKey(attributeDescriptor);
- tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor;
- tabptr.p->keyAttr[i].charsetInfo = cs;
- i++;
- }
- ndbrequire(i == noOfKeyAttr);
- releaseSections(signal);
+
+ const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tabptr.i);
+ ndbrequire(noOfKeyAttr == desc->noOfKeyAttr);
ndbrequire(tabptr.p->enabled == false);
tabptr.p->enabled = true;
tabptr.p->dropping = false;
- tabptr.p->noOfKeyAttr = noOfKeyAttr;
- tabptr.p->hasCharAttr = hasCharAttr;
- tabptr.p->noOfDistrKeys = noOfDistrKeys;
+ tabptr.p->noOfKeyAttr = desc->noOfKeyAttr;
+ tabptr.p->hasCharAttr = desc->hasCharAttr;
+ tabptr.p->noOfDistrKeys = desc->noOfDistrKeys;
signal->theData[0] = tabptr.i;
signal->theData[1] = retPtr;
@@ -2323,113 +2298,37 @@ Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen,
Uint32 tabPtrI,
bool distr)
{
- Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * 4 * MAX_XFRM_MULTIPLY];
- const Uint32 dstSize = sizeof(Tmp) / 4;
+ Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY];
const TableRecord* tabPtrP = &tableRecord[tabPtrI];
- const Uint32 noOfKeyAttr = tabPtrP->noOfKeyAttr;
- Uint32 noOfDistrKeys = tabPtrP->noOfDistrKeys;
const bool hasCharAttr = tabPtrP->hasCharAttr;
+ const bool hasDistKeys = tabPtrP->noOfDistrKeys > 0;
Uint32 *dst = (Uint32*)Tmp;
Uint32 dstPos = 0;
- Uint32 srcPos = 0;
Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
- if(hasCharAttr){
- Uint32 i = 0;
- while (i < noOfKeyAttr) {
- const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
-
- Uint32 srcBytes =
- AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
- Uint32 srcWords = (srcBytes + 3) / 4;
- Uint32 dstWords = ~0;
- uchar* dstPtr = (uchar*)&dst[dstPos];
- const uchar* srcPtr = (const uchar*)&src[srcPos];
- CHARSET_INFO* cs = keyAttr.charsetInfo;
-
- if (cs == NULL) {
- jam();
- memcpy(dstPtr, srcPtr, srcWords << 2);
- dstWords = srcWords;
- } else {
- jam();
- Uint32 typeId =
- AttributeDescriptor::getType(keyAttr.attributeDescriptor);
- Uint32 lb, len;
- bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
- ndbrequire(ok);
- Uint32 xmul = cs->strxfrm_multiply;
- if (xmul == 0)
- xmul = 1;
- /*
- * Varchar is really Char. End spaces do not matter. To get
- * same hash we blank-pad to maximum length via strnxfrm.
- * TODO use MySQL charset-aware hash function instead
- */
- Uint32 dstLen = xmul * (srcBytes - lb);
- ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
- int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
- ndbrequire(n != -1);
- while ((n & 3) != 0) {
- dstPtr[n++] = 0;
- }
- dstWords = (n >> 2);
- }
- dstPos += dstWords;
- srcPos += srcWords;
- keyPartLen[i++] = dstWords;
- }
+ Uint32 * keyPartLenPtr;
+ if(hasCharAttr)
+ {
+ keyPartLenPtr = keyPartLen;
+ dstPos = xfrm_key(tabPtrI, src, dst, sizeof(Tmp) >> 2, keyPartLenPtr);
+ ndbrequire(dstPos);
}
else
{
dst = src;
dstPos = srcLen;
+ keyPartLenPtr = 0;
}
md5_hash(dstHash, (Uint64*)dst, dstPos);
- if(distr && noOfDistrKeys)
+ if(distr && hasDistKeys)
{
jam();
- src = dst;
- dstPos = 0;
- Uint32 i = 0;
- if(hasCharAttr)
- {
- while (i < noOfKeyAttr && noOfDistrKeys)
- {
- const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
- Uint32 len = keyPartLen[i];
- if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor))
- {
- noOfDistrKeys--;
- memmove(dst+dstPos, src, len << 2);
- dstPos += len;
- }
- src += len;
- i++;
- }
- }
- else
- {
- while (i < noOfKeyAttr && noOfDistrKeys)
- {
- const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
- Uint32 len =
- AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
- len = (len + 3) / 4;
- if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor))
- {
- noOfDistrKeys--;
- memmove(dst+dstPos, src, len << 2);
- dstPos += len;
- }
- src += len;
- i++;
- }
- }
+
Uint32 tmp[4];
- md5_hash(tmp, (Uint64*)dst, dstPos);
+ Uint32 len = create_distr_key(tabPtrI, dst, keyPartLenPtr);
+ md5_hash(tmp, (Uint64*)dst, len);
dstHash[1] = tmp[1];
}
return true; // success
@@ -3347,7 +3246,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal,
lqhKeyReq->tcBlockref = sig4;
lqhKeyReq->savePointId = sig5;
- sig0 = regCachePtr->tableref + (regCachePtr->schemaVersion << 16);
+ sig0 = regCachePtr->tableref + ((regCachePtr->schemaVersion << 16) & 0xFFFF0000);
sig1 = regCachePtr->fragmentid + (regTcPtr->tcNodedata[1] << 16);
sig2 = regApiPtr->transid[0];
sig3 = regApiPtr->transid[1];
@@ -10204,10 +10103,6 @@ void Dbtc::initTable(Signal* signal)
tabptr.p->noOfKeyAttr = 0;
tabptr.p->hasCharAttr = 0;
tabptr.p->noOfDistrKeys = 0;
- for (unsigned k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) {
- tabptr.p->keyAttr[k].attributeDescriptor = 0;
- tabptr.p->keyAttr[k].charsetInfo = 0;
- }
}//for
}//Dbtc::initTable()
@@ -13137,7 +13032,7 @@ Dbtc::TableRecord::getErrorCode(Uint32 schemaVersion) const {
return ZNO_SUCH_TABLE;
if(dropping)
return ZDROP_TABLE_IN_PROGRESS;
- if(schemaVersion != currentSchemaVersion)
+ if(table_version_major(schemaVersion) != table_version_major(currentSchemaVersion))
return ZWRONG_SCHEMA_VERSION_ERROR;
ErrorReporter::handleAssert("Dbtc::TableRecord::getErrorCode",
__FILE__, __LINE__);
diff --git a/storage/ndb/src/kernel/blocks/grep/Grep.cpp b/storage/ndb/src/kernel/blocks/grep/Grep.cpp
deleted file mode 100644
index 0527c5415ab..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/Grep.cpp
+++ /dev/null
@@ -1,2010 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "Grep.hpp"
-#include <ndb_version.h>
-
-#include <NdbTCP.h>
-#include <Bitmask.hpp>
-
-#include <signaldata/NodeFailRep.hpp>
-#include <signaldata/ReadNodesConf.hpp>
-#include <signaldata/CheckNodeGroups.hpp>
-#include <signaldata/GrepImpl.hpp>
-#include <signaldata/RepImpl.hpp>
-#include <signaldata/EventReport.hpp>
-#include <signaldata/DictTabInfo.hpp>
-#include <signaldata/GetTabInfo.hpp>
-#include <signaldata/WaitGCP.hpp>
-#include <GrepEvent.hpp>
-#include <AttributeHeader.hpp>
-
-#define CONTINUEB_DELAY 500
-#define SSREPBLOCKNO 2
-#define PSREPBLOCKNO 2
-
-//#define DEBUG_GREP
-//#define DEBUG_GREP_SUBSCRIPTION
-//#define DEBUG_GREP_TRANSFER
-//#define DEBUG_GREP_APPLY
-//#define DEBUG_GREP_DELETE
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: STARTUP of GREP Block, etc
- * ------------------------------------------------------------------------
- **************************************************************************/
-static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE;
-void
-Grep::getNodeGroupMembers(Signal* signal) {
- jam();
- /**
- * Ask DIH for nodeGroupMembers
- */
- CheckNodeGroups * sd = (CheckNodeGroups*)signal->getDataPtrSend();
- sd->blockRef = reference();
- sd->requestType =
- CheckNodeGroups::Direct |
- CheckNodeGroups::GetNodeGroupMembers;
- sd->nodeId = getOwnNodeId();
- EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal,
- CheckNodeGroups::SignalLength);
- jamEntry();
-
- c_nodeGroup = sd->output;
- c_noNodesInGroup = 0;
- for (int i = 0; i < MAX_NDB_NODES; i++) {
- if (sd->mask.get(i)) {
- if (i == getOwnNodeId()) c_idInNodeGroup = c_noNodesInGroup;
- c_nodesInGroup[c_noNodesInGroup] = i;
- c_noNodesInGroup++;
- }
- }
- ndbrequire(c_noNodesInGroup > 0); // at least 1 node in the nodegroup
-
-#ifdef NODEFAIL_DEBUG
- for (Uint32 i = 0; i < c_noNodesInGroup; i++) {
- ndbout_c ("Grep: NodeGroup %u, me %u, me in group %u, member[%u] %u",
- c_nodeGroup, getOwnNodeId(), c_idInNodeGroup,
- i, c_nodesInGroup[i]);
- }
-#endif
-}
-
-
-void
-Grep::execSTTOR(Signal* signal)
-{
- jamEntry();
- const Uint32 startphase = signal->theData[1];
- const Uint32 typeOfStart = signal->theData[7];
- if (startphase == 3)
- {
- jam();
- signal->theData[0] = reference();
- g_TypeOfStart = typeOfStart;
- sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB);
- return;
- }
- if(startphase == 5) {
- jam();
- /**
- * we don't want any log/meta records comming to use
- * until we are done with the recovery.
- */
- if (g_TypeOfStart == NodeState::ST_NODE_RESTART) {
- jam();
- pspart.m_recoveryMode = true;
- getNodeGroupMembers(signal);
- for (Uint32 i = 0; i < c_noNodesInGroup; i++) {
- Uint32 ref =numberToRef(GREP, c_nodesInGroup[i]);
- if (ref != reference())
- sendSignal(ref, GSN_GREP_START_ME, signal,
- 1 /*SumaStartMe::SignalLength*/, JBB);
- }
- } else pspart.m_recoveryMode = false;
-
- }
-
- if(startphase == 7) {
- jam();
- if (g_TypeOfStart == NodeState::ST_NODE_RESTART) {
- pspart.m_recoveryMode = false;
- }
- }
-
- sendSTTORRY(signal);
-}
-
-
-void
-Grep::PSPart::execSTART_ME(Signal* signal)
-{
- jamEntry();
- GrepStartMe * me =(GrepStartMe*)signal->getDataPtr();
- BlockReference ref = me->senderRef;
- GrepAddSubReq* const addReq = (GrepAddSubReq *)signal->getDataPtr();
-
-
- SubscriptionPtr subPtr;
- c_subscriptions.first(c_subPtr);
- for(; !c_subPtr.isNull(); c_subscriptions.next(c_subPtr)) {
- jam();
- subPtr.i = c_subPtr.curr.i;
- subPtr.p = c_subscriptions.getPtr(subPtr.i);
- addReq->subscriptionId = subPtr.p->m_subscriptionId;
- addReq->subscriptionKey = subPtr.p->m_subscriptionKey;
- addReq->subscriberData = subPtr.p->m_subscriberData;
- addReq->subscriptionType = subPtr.p->m_subscriptionType;
- addReq->senderRef = subPtr.p->m_coordinatorRef;
- addReq->subscriberRef =subPtr.p->m_subscriberRef;
-
- sendSignal(ref,
- GSN_GREP_ADD_SUB_REQ,
- signal,
- GrepAddSubReq::SignalLength,
- JBB);
- }
-
- addReq->subscriptionId = 0;
- addReq->subscriptionKey = 0;
- addReq->subscriberData = 0;
- addReq->subscriptionType = 0;
- addReq->senderRef = 0;
- addReq->subscriberRef = 0;
-
- sendSignal(ref,
- GSN_GREP_ADD_SUB_REQ,
- signal,
- GrepAddSubReq::SignalLength,
- JBB);
-}
-
-void
-Grep::PSPart::execGREP_ADD_SUB_REQ(Signal* signal)
-{
- jamEntry();
- GrepAddSubReq * const grepReq = (GrepAddSubReq *)signal->getDataPtr();
- const Uint32 subId = grepReq->subscriptionId;
- const Uint32 subKey = grepReq->subscriptionKey;
- const Uint32 subData = grepReq->subscriberData;
- const Uint32 subType = grepReq->subscriptionType;
- const Uint32 coordinatorRef = grepReq->senderRef;
-
- /**
- * this is ref to the REP node for this subscription.
- */
- const Uint32 subRef = grepReq->subscriberRef;
-
- if(subId!=0 && subKey!=0) {
- jam();
- SubscriptionPtr subPtr;
- ndbrequire( c_subscriptionPool.seize(subPtr));
- subPtr.p->m_coordinatorRef = coordinatorRef;
- subPtr.p->m_subscriptionId = subId;
- subPtr.p->m_subscriptionKey = subKey;
- subPtr.p->m_subscriberRef = subRef;
- subPtr.p->m_subscriberData = subData;
- subPtr.p->m_subscriptionType = subType;
-
- c_subscriptions.add(subPtr);
- }
- else {
- jam();
- GrepAddSubConf * conf = (GrepAddSubConf *)grepReq;
- conf->noOfSub =
- c_subscriptionPool.getSize()-c_subscriptionPool.getNoOfFree();
- sendSignal(signal->getSendersBlockRef(),
- GSN_GREP_ADD_SUB_CONF,
- signal,
- GrepAddSubConf::SignalLength,
- JBB);
- }
-}
-
-void
-Grep::PSPart::execGREP_ADD_SUB_REF(Signal* signal)
-{
- /**
- * @todo fix error stuff
- */
-}
-
-void
-Grep::PSPart::execGREP_ADD_SUB_CONF(Signal* signal)
-{
- jamEntry();
- GrepAddSubConf* const conf = (GrepAddSubConf *)signal->getDataPtr();
- Uint32 noOfSubscriptions = conf->noOfSub;
- Uint32 noOfRestoredSubscriptions =
- c_subscriptionPool.getSize()-c_subscriptionPool.getNoOfFree();
- if(noOfSubscriptions!=noOfRestoredSubscriptions) {
- jam();
- /**
- *@todo send ref signal
- */
- ndbrequire(false);
- }
-}
-
-void
-Grep::execREAD_NODESCONF(Signal* signal)
-{
- jamEntry();
- ReadNodesConf * conf = (ReadNodesConf *)signal->getDataPtr();
-
-#if 0
- ndbout_c("Grep: Recd READ_NODESCONF");
-#endif
-
- /******************************
- * Check which REP nodes exist
- ******************************/
- Uint32 i;
- for (i = 1; i < MAX_NODES; i++)
- {
- jam();
-#if 0
- ndbout_c("Grep: Found node %d of type %d", i, getNodeInfo(i).getType());
-#endif
- if (getNodeInfo(i).getType() == NodeInfo::REP)
- {
- jam();
- /**
- * @todo This should work for more than ONE rep node!
- */
- pscoord.m_repRef = numberToRef(PSREPBLOCKNO, i);
- pspart.m_repRef = numberToRef(PSREPBLOCKNO, i);
-#if 0
- ndbout_c("Grep: REP node %d detected", i);
-#endif
- }
- }
-
- /*****************************
- * Check which DB nodes exist
- *****************************/
- m_aliveNodes.clear();
-
- Uint32 count = 0;
- for(i = 0; i<MAX_NDB_NODES; i++)
- {
- if (NodeBitmask::get(conf->allNodes, i))
- {
- jam();
- count++;
-
- NodePtr node;
- ndbrequire(m_nodes.seize(node));
-
- node.p->nodeId = i;
- if (NodeBitmask::get(conf->inactiveNodes, i))
- {
- node.p->alive = 0;
- }
- else
- {
- node.p->alive = 1;
- m_aliveNodes.set(i);
- }
- }
- }
- m_masterNodeId = conf->masterNodeId;
- ndbrequire(count == conf->noOfNodes);
- sendSTTORRY(signal);
-}
-
-void
-Grep::sendSTTORRY(Signal* signal)
-{
- signal->theData[0] = 0;
- signal->theData[3] = 1;
- signal->theData[4] = 3;
- signal->theData[5] = 5;
- signal->theData[6] = 7;
- signal->theData[7] = 255; // No more start phases from missra
- sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 8, JBB);
-}
-
-void
-Grep::execNDB_STTOR(Signal* signal)
-{
- jamEntry();
-}
-
-void
-Grep::execDUMP_STATE_ORD(Signal* signal)
-{
- jamEntry();
- //Uint32 tCase = signal->theData[0];
-
-#if 0
- if(sscoord.m_repRef == 0)
- {
- ndbout << "Grep: Recd DUMP signal but has no connection with REP node"
- << endl;
- return;
- }
-#endif
-
- /*
- switch (tCase)
- {
- case 8100: sscoord.grepReq(signal, GrepReq::START_SUBSCR); break;
- case 8102: sscoord.grepReq(signal, GrepReq::START_METALOG); break;
- case 8104: sscoord.grepReq(signal, GrepReq::START_METASCAN); break;
- case 8106: sscoord.grepReq(signal, GrepReq::START_DATALOG); break;
- case 8108: sscoord.grepReq(signal, GrepReq::START_DATASCAN); break;
- case 8110: sscoord.grepReq(signal, GrepReq::STOP_SUBSCR); break;
- case 8500: sscoord.grepReq(signal, GrepReq::REMOVE_BUFFERS); break;
- case 8300: sscoord.grepReq(signal, GrepReq::SLOWSTOP); break;
- case 8400: sscoord.grepReq(signal, GrepReq::FASTSTOP); break;
- case 8600: sscoord.grepReq(signal, GrepReq::CREATE_SUBSCR); break;
- case 8700: sscoord.dropTable(signal,(Uint32)signal->theData[1]);break;
- default: break;
- }
- */
-}
-
-/**
- * Signal received when REP node has failed
- */
-void
-Grep::execAPI_FAILREQ(Signal* signal)
-{
- jamEntry();
- //Uint32 failedApiNode = signal->theData[0];
- //BlockReference retRef = signal->theData[1];
-
- /**
- * @todo We should probably do something smart if the
- * PS REP node fails???? /Lars
- */
-
-#if 0
- ndbout_c("Grep: API_FAILREQ received for API node %d.", failedApiNode);
-#endif
-
- /**
- * @note This signal received is NOT allowed to send any CONF
- * signal, since this would screw up TC/DICT to API
- * "connections".
- */
-}
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: GREP Control
- * ------------------------------------------------------------------------
- **************************************************************************/
-void
-Grep::execGREP_REQ(Signal* signal)
-{
- jamEntry();
-
- //GrepReq * req = (GrepReq *)signal->getDataPtr();
-
- /**
- * @todo Fix so that request is redirected to REP Server
- * Obsolete?
- * Was: sscoord.grepReq(signal, req->request);
- */
- ndbout_c("Warning! REP commands can only be executed at REP SERVER prompt!");
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: NODE STATE HANDLING
- * ------------------------------------------------------------------------
- **************************************************************************/
-void
-Grep::execNODE_FAILREP(Signal* signal)
-{
- jamEntry();
- NodeFailRep * rep = (NodeFailRep*)signal->getDataPtr();
- bool changed = false;
-
- NodePtr nodePtr;
- for(m_nodes.first(nodePtr); nodePtr.i != RNIL; m_nodes.next(nodePtr))
- {
- jam();
- if (NodeBitmask::get(rep->theNodes, nodePtr.p->nodeId))
- {
- jam();
-
- if (nodePtr.p->alive)
- {
- jam();
- ndbassert(m_aliveNodes.get(nodePtr.p->nodeId));
- changed = true;
- }
- else
- {
- ndbassert(!m_aliveNodes.get(nodePtr.p->nodeId));
- }
-
- nodePtr.p->alive = 0;
- m_aliveNodes.clear(nodePtr.p->nodeId);
- }
- }
-
-
- /**
- * Problem: Fix a node failure running a protocol
- *
- * 1. Coordinator node of a protocol dies
- * - Elect a new coordinator
- * - send ref to user
- *
- * 2. Non-coordinator dies.
- * - make coordinator aware of this
- * so that coordinator does not wait for
- * conf from faulty node
- * - node recovery will restore the non-coordinator.
- *
- */
-}
-
-void
-Grep::execINCL_NODEREQ(Signal* signal)
-{
- jamEntry();
-
- //const Uint32 senderRef = signal->theData[0];
- const Uint32 inclNode = signal->theData[1];
-
- NodePtr node;
- for(m_nodes.first(node); node.i != RNIL; m_nodes.next(node))
- {
- jam();
- const Uint32 nodeId = node.p->nodeId;
- if (inclNode == nodeId) {
- jam();
-
- ndbrequire(node.p->alive == 0);
- ndbassert(!m_aliveNodes.get(nodeId));
-
- node.p->alive = 1;
- m_aliveNodes.set(nodeId);
-
- break;
- }
- }
-
- /**
- * @todo: if we include this DIH's got to be prepared, later if needed...
- */
-#if 0
- signal->theData[0] = reference();
-
- sendSignal(senderRef, GSN_INCL_NODECONF, signal, 1, JBB);
-#endif
-}
-
-
-/**
- * Helper methods
- */
-void
-Grep::PSCoord::prepareOperationRec(SubCoordinatorPtr subPtr,
- BlockReference subscriber,
- Uint32 subId,
- Uint32 subKey,
- Uint32 request)
-{
- subPtr.p->m_coordinatorRef = reference();
- subPtr.p->m_subscriberRef = subscriber;
- subPtr.p->m_subscriberData = subPtr.i;
- subPtr.p->m_subscriptionId = subId;
- subPtr.p->m_subscriptionKey = subKey;
- subPtr.p->m_outstandingRequest = request;
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: CREATE SUBSCRIPTION ID
- * ------------------------------------------------------------------------
- *
- * Requests SUMA to create a unique subscription id
- **************************************************************************/
-
-void
-Grep::PSCoord::execGREP_CREATE_SUBID_REQ(Signal* signal)
-{
- jamEntry();
-
- CreateSubscriptionIdReq * req =
- (CreateSubscriptionIdReq*)signal->getDataPtr();
- BlockReference ref = signal->getSendersBlockRef();
-
- SubCoordinatorPtr subPtr;
- if( !c_subCoordinatorPool.seize(subPtr)) {
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef = ref;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sendRefToSS(signal, sub, GrepError::SUBSCRIPTION_ID_NOMEM );
- return;
- }
- prepareOperationRec(subPtr,
- ref,
- 0,0,
- GSN_CREATE_SUBID_REQ);
-
-
- ndbout_c("SUBID_REQ Ref %d",ref);
- req->senderData=subPtr.p->m_subscriberData;
-
- sendSignal(SUMA_REF, GSN_CREATE_SUBID_REQ, signal,
- SubCreateReq::SignalLength, JBB);
-
-#if 1 //def DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSCoord: Sent CREATE_SUBID_REQ to SUMA");
-#endif
-}
-
-void
-Grep::PSCoord::execCREATE_SUBID_CONF(Signal* signal)
-{
- jamEntry();
- CreateSubscriptionIdConf const * conf =
- (CreateSubscriptionIdConf *)signal->getDataPtr();
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 subData = conf->subscriberData;
-
-#if 1 //def DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSCoord: Recd GREP_SUBID_CONF (subId:%d, subKey:%d)",
- subId, subKey);
-#endif
-
- SubCoordinatorPtr subPtr;
- c_subCoordinatorPool.getPtr(subPtr, subData);
- BlockReference repRef = subPtr.p->m_subscriberRef;
-
- { // Check that id/key is unique
- SubCoordinator key;
- SubCoordinatorPtr tmp;
- key.m_subscriptionId = subId;
- key.m_subscriptionKey = subKey;
- if(c_runningSubscriptions.find(tmp, key)){
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef=repRef;
- sub.m_subscriptionId = subId;
- sub.m_subscriptionKey = subKey;
- sendRefToSS(signal,sub, GrepError::SUBSCRIPTION_ID_NOT_UNIQUE );
- return;
- }
- }
-
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_CREATE_SUBID_CONF, signal,
- CreateSubscriptionIdConf::SignalLength, JBB);
- c_subCoordinatorPool.release(subData);
-
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionInfo,
- GrepEvent::GrepPS_CreateSubIdConf,
- subId,
- subKey,
- (Uint32)GrepError::GE_NO_ERROR);
-}
-
-void
-Grep::PSCoord::execCREATE_SUBID_REF(Signal* signal) {
- jamEntry();
- CreateSubscriptionIdRef const * ref =
- (CreateSubscriptionIdRef *)signal->getDataPtr();
- Uint32 subData = ref->subscriberData;
- GrepError::GE_Code err;
-
- Uint32 sendersBlockRef = signal->getSendersBlockRef();
- if(sendersBlockRef == SUMA_REF)
- {
- jam();
- err = GrepError::SUBSCRIPTION_ID_SUMA_FAILED_CREATE;
- } else {
- jam();
- ndbrequire(false); /* Added since errorcode err unhandled
- * TODO: fix correct errorcode
- */
- err= GrepError::GE_NO_ERROR; // remove compiler warning
- }
-
- SubCoordinatorPtr subPtr;
- c_runningSubscriptions.getPtr(subPtr, subData);
- BlockReference repref = subPtr.p->m_subscriberRef;
-
- SubCoordinator sub;
- sub.m_subscriberRef = repref;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sendRefToSS(signal,sub, err);
-
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: CREATE SUBSCRIPTION
- * ------------------------------------------------------------------------
- *
- * Creates a subscription for every GREP to its local SUMA.
- * GREP node that executes createSubscription becomes the GREP Coord.
- **************************************************************************/
-
-/**
- * Request to create a subscription (sent from SS)
- */
-void
-Grep::PSCoord::execGREP_SUB_CREATE_REQ(Signal* signal)
-{
- jamEntry();
- GrepSubCreateReq const * grepReq = (GrepSubCreateReq *)signal->getDataPtr();
- Uint32 subId = grepReq->subscriptionId;
- Uint32 subKey = grepReq->subscriptionKey;
- Uint32 subType = grepReq->subscriptionType;
- BlockReference rep = signal->getSendersBlockRef();
-
- GrepCreateReq * req =(GrepCreateReq*)grepReq;
-
- SubCoordinatorPtr subPtr;
-
- if( !c_subCoordinatorPool.seize(subPtr)) {
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef = rep;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sub.m_outstandingRequest = GSN_GREP_CREATE_REQ;
- sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL);
- return;
- }
- prepareOperationRec(subPtr,
- numberToRef(PSREPBLOCKNO, refToNode(rep)), subId, subKey,
- GSN_GREP_CREATE_REQ);
-
- /* Get the payload of the signal.
- */
- SegmentedSectionPtr selectedTablesPtr;
- if(subType == SubCreateReq::SelectiveTableSnapshot) {
- jam();
- ndbrequire(signal->getNoOfSections()==1);
- signal->getSection(selectedTablesPtr,0);
- signal->header.m_noOfSections = 0;
- }
- /**
- * Prepare the signal to be sent to Grep participatns
- */
- subPtr.p->m_subscriptionType = subType;
- req->senderRef = reference();
- req->subscriberRef = numberToRef(PSREPBLOCKNO, refToNode(rep));
- req->subscriberData = subPtr.p->m_subscriberData;
- req->subscriptionId = subId;
- req->subscriptionKey = subKey;
- req->subscriptionType = subType;
-
- /*add payload if it is a selectivetablesnap*/
- if(subType == SubCreateReq::SelectiveTableSnapshot) {
- jam();
- signal->setSection(selectedTablesPtr, 0);
- }
-
- /******************************
- * Send to all PS participants
- ******************************/
- NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes);
- subPtr.p->m_outstandingParticipants = rg;
- sendSignal(rg,
- GSN_GREP_CREATE_REQ, signal,
- GrepCreateReq::SignalLength, JBB);
-
-
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSCoord: Sent GREP_CREATE_REQ "
- "(subId:%d, subKey:%d, subData:%d, subType:%d) to parts",
- subId, subKey, subPtr.p->m_subscriberData, subType);
-#endif
-}
-
-void
-Grep::PSPart::execGREP_CREATE_REQ(Signal* signal)
-{
- jamEntry();
- GrepCreateReq * const grepReq = (GrepCreateReq *)signal->getDataPtr();
- const Uint32 subId = grepReq->subscriptionId;
- const Uint32 subKey = grepReq->subscriptionKey;
- const Uint32 subData = grepReq->subscriberData;
- const Uint32 subType = grepReq->subscriptionType;
- const Uint32 coordinatorRef = grepReq->senderRef;
- const Uint32 subRef = grepReq->subscriberRef; //this is ref to the
- //REP node for this
- //subscription.
-
- SubscriptionPtr subPtr;
- ndbrequire( c_subscriptionPool.seize(subPtr));
- subPtr.p->m_coordinatorRef = coordinatorRef;
- subPtr.p->m_subscriptionId = subId;
- subPtr.p->m_subscriptionKey = subKey;
- subPtr.p->m_subscriberRef = subRef;
- subPtr.p->m_subscriberData = subPtr.i;
- subPtr.p->m_subscriptionType = subType;
- subPtr.p->m_outstandingRequest = GSN_GREP_CREATE_REQ;
- subPtr.p->m_operationPtrI = subData;
-
- c_subscriptions.add(subPtr);
-
- SegmentedSectionPtr selectedTablesPtr;
- if(subType == SubCreateReq::SelectiveTableSnapshot) {
- jam();
- ndbrequire(signal->getNoOfSections()==1);
- signal->getSection(selectedTablesPtr,0);// SubCreateReq::TABLE_LIST);
- signal->header.m_noOfSections = 0;
- }
-
- /**
- * Prepare signal to be sent to SUMA
- */
- SubCreateReq * sumaReq = (SubCreateReq *)grepReq;
- sumaReq->subscriberRef = GREP_REF;
- sumaReq->subscriberData = subPtr.p->m_subscriberData;
- sumaReq->subscriptionId = subPtr.p->m_subscriptionId;
- sumaReq->subscriptionKey = subPtr.p->m_subscriptionKey;
- sumaReq->subscriptionType = subPtr.p->m_subscriptionType;
- /*add payload if it is a selectivetablesnap*/
- if(subType == SubCreateReq::SelectiveTableSnapshot) {
- jam();
- signal->setSection(selectedTablesPtr, 0);
- }
- sendSignal(SUMA_REF,
- GSN_SUB_CREATE_REQ,
- signal,
- SubCreateReq::SignalLength,
- JBB);
-}
-
-void
-Grep::PSPart::execSUB_CREATE_CONF(Signal* signal)
-{
- jamEntry();
-
- SubCreateConf * const conf = (SubCreateConf *)signal->getDataPtr();
- Uint32 subData = conf->subscriberData;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- /**
- @todo check why this can fuck up -johan
-
- ndbrequire(subPtr.p->m_subscriptionId == conf->subscriptionId);
- ndbrequire(subPtr.p->m_subscriptionKey == conf->subscriptionKey);
- */
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSPart: Recd SUB_CREATE_CONF "
- "(subId:%d, subKey:%d) from SUMA",
- conf->subscriptionId, conf->subscriptionKey);
-#endif
-
- /*********************
- * Send conf to coord
- *********************/
- GrepCreateConf * grepConf = (GrepCreateConf*)conf;
- grepConf->senderNodeId = getOwnNodeId();
- grepConf->senderData = subPtr.p->m_operationPtrI;
- sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_CREATE_CONF, signal,
- GrepCreateConf::SignalLength, JBB);
- subPtr.p->m_outstandingRequest = 0;
-}
-
-/**
- * Handle errors that either occured in:
- * 1) PSPart
- * or
- * 2) propagated from local SUMA
- */
-void
-Grep::PSPart::execSUB_CREATE_REF(Signal* signal)
-{
- jamEntry();
- SubCreateRef * const ref = (SubCreateRef *)signal->getDataPtr();
- Uint32 subData = ref->subscriberData;
- GrepError::GE_Code err = (GrepError::GE_Code)ref->err;
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- sendRefToPSCoord(signal, *subPtr.p, err /*error*/);
- subPtr.p->m_outstandingRequest = 0;
-}
-
-void
-Grep::PSCoord::execGREP_CREATE_CONF(Signal* signal)
-{
- jamEntry();
- GrepCreateConf const * conf = (GrepCreateConf *)signal->getDataPtr();
- Uint32 subData = conf->senderData;
- Uint32 nodeId = conf->senderNodeId;
-
- SubCoordinatorPtr subPtr;
- c_subCoordinatorPool.getPtr(subPtr, subData);
-
- ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_CREATE_REQ);
-
- subPtr.p->m_outstandingParticipants.clearWaitingFor(nodeId);
-
- if(!subPtr.p->m_outstandingParticipants.done()) return;
- /********************************
- * All participants have CONF:ed
- ********************************/
- Uint32 subId = subPtr.p->m_subscriptionId;
- Uint32 subKey = subPtr.p->m_subscriptionKey;
-
- GrepSubCreateConf * grepConf = (GrepSubCreateConf *)signal->getDataPtr();
- grepConf->subscriptionId = subId;
- grepConf->subscriptionKey = subKey;
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_CREATE_CONF, signal,
- GrepSubCreateConf::SignalLength, JBB);
-
- /**
- * Send event report
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionInfo,
- GrepEvent::GrepPS_SubCreateConf,
- subId,
- subKey,
- (Uint32)GrepError::GE_NO_ERROR);
-
- c_subCoordinatorPool.release(subPtr);
-
-}
-
-/**
- * Handle errors that either occured in:
- * 1) PSCoord
- * or
- * 2) propagated from PSPart
- */
-void
-Grep::PSCoord::execGREP_CREATE_REF(Signal* signal)
-{
- jamEntry();
- GrepCreateRef * const ref = (GrepCreateRef *)signal->getDataPtr();
- Uint32 subData = ref->senderData;
- Uint32 err = ref->err;
- SubCoordinatorPtr subPtr;
- c_runningSubscriptions.getPtr(subPtr, subData);
-
- sendRefToSS(signal, *subPtr.p, (GrepError::GE_Code)err /*error*/);
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: START SUBSCRIPTION
- * ------------------------------------------------------------------------
- *
- * Starts a subscription at SUMA.
- * Each participant starts its own subscription.
- **************************************************************************/
-
-/**
- * Request to start subscription (Sent from SS)
- */
-void
-Grep::PSCoord::execGREP_SUB_START_REQ(Signal* signal)
-{
- jamEntry();
- GrepSubStartReq * const subReq = (GrepSubStartReq *)signal->getDataPtr();
- SubscriptionData::Part part = (SubscriptionData::Part) subReq->part;
- Uint32 subId = subReq->subscriptionId;
- Uint32 subKey = subReq->subscriptionKey;
- BlockReference rep = signal->getSendersBlockRef();
-
- SubCoordinatorPtr subPtr;
-
- if(!c_subCoordinatorPool.seize(subPtr)) {
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef = rep;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sub.m_outstandingRequest = GSN_GREP_START_REQ;
- sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL);
- return;
- }
-
- prepareOperationRec(subPtr,
- numberToRef(PSREPBLOCKNO, refToNode(rep)),
- subId, subKey,
- GSN_GREP_START_REQ);
-
- GrepStartReq * const req = (GrepStartReq *) subReq;
- req->part = (Uint32) part;
- req->subscriptionId = subPtr.p->m_subscriptionId;
- req->subscriptionKey = subPtr.p->m_subscriptionKey;
- req->senderData = subPtr.p->m_subscriberData;
-
- /***************************
- * Send to all participants
- ***************************/
- NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes);
- subPtr.p->m_outstandingParticipants = rg;
- sendSignal(rg,
- GSN_GREP_START_REQ,
- signal,
- GrepStartReq::SignalLength, JBB);
-
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSCoord: Sent GREP_START_REQ "
- "(subId:%d, subKey:%d, senderData:%d, part:%d) to all participants",
- req->subscriptionId, req->subscriptionKey, req->senderData, part);
-#endif
-}
-
-
-void
-Grep::PSPart::execGREP_START_REQ(Signal* signal)
-{
- jamEntry();
- GrepStartReq * const grepReq = (GrepStartReq *) signal->getDataPtr();
- SubscriptionData::Part part = (SubscriptionData::Part)grepReq->part;
- Uint32 subId = grepReq->subscriptionId;
- Uint32 subKey = grepReq->subscriptionKey;
- Uint32 operationPtrI = grepReq->senderData;
-
- Subscription key;
- key.m_subscriptionId = subId;
- key.m_subscriptionKey = subKey;
- SubscriptionPtr subPtr;
- ndbrequire(c_subscriptions.find(subPtr, key));;
- subPtr.p->m_outstandingRequest = GSN_GREP_START_REQ;
- subPtr.p->m_operationPtrI = operationPtrI;
- /**
- * send SUB_START_REQ to local SUMA
- */
- SubStartReq * sumaReq = (SubStartReq *) grepReq;
- sumaReq->subscriptionId = subId;
- sumaReq->subscriptionKey = subKey;
- sumaReq->subscriberData = subPtr.i;
- sumaReq->part = (Uint32) part;
-
- sendSignal(SUMA_REF, GSN_SUB_START_REQ, signal,
- SubStartReq::SignalLength, JBB);
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSPart: Sent SUB_START_REQ (subId:%d, subKey:%d, part:%d)",
- subId, subKey, (Uint32)part);
-#endif
-}
-
-
-void
-Grep::PSPart::execSUB_START_CONF(Signal* signal)
-{
- jamEntry();
-
- SubStartConf * const conf = (SubStartConf *) signal->getDataPtr();
- SubscriptionData::Part part = (SubscriptionData::Part)conf->part;
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 subData = conf->subscriberData;
- Uint32 firstGCI = conf->firstGCI;
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSPart: Recd SUB_START_CONF "
- "(subId:%d, subKey:%d, subData:%d)",
- subId, subKey, subData);
-#endif
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- ndbrequire(subPtr.p->m_subscriptionId == subId);
- ndbrequire(subPtr.p->m_subscriptionKey == subKey);
-
- GrepStartConf * grepConf = (GrepStartConf *)conf;
- grepConf->senderData = subPtr.p->m_operationPtrI;
- grepConf->part = (Uint32) part;
- grepConf->subscriptionKey = subKey;
- grepConf->subscriptionId = subId;
- grepConf->firstGCI = firstGCI;
- grepConf->senderNodeId = getOwnNodeId();
- sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_START_CONF, signal,
- GrepStartConf::SignalLength, JBB);
- subPtr.p->m_outstandingRequest = 0;
-
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSPart: Sent GREP_START_CONF "
- "(subId:%d, subKey:%d, subData:%d, part:%d)",
- subId, subKey, subData, part);
-#endif
-}
-
-
-/**
- * Handle errors that either occured in:
- * 1) PSPart
- * or
- * 2) propagated from local SUMA
- *
- * Propagates REF signal to PSCoord
- */
-void
-Grep::PSPart::execSUB_START_REF(Signal* signal)
-{
- SubStartRef * const ref = (SubStartRef *)signal->getDataPtr();
- Uint32 subData = ref->subscriberData;
- GrepError::GE_Code err = (GrepError::GE_Code)ref->err;
- SubscriptionData::Part part = (SubscriptionData::Part)ref->part;
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- sendRefToPSCoord(signal, *subPtr.p, err /*error*/, part);
- subPtr.p->m_outstandingRequest = 0;
-}
-
-
-/**
- * Logging has started... (says PS Participant)
- */
-void
-Grep::PSCoord::execGREP_START_CONF(Signal* signal)
-{
- jamEntry();
-
- GrepStartConf * const conf = (GrepStartConf *) signal->getDataPtr();
- Uint32 subData = conf->senderData;
- SubscriptionData::Part part = (SubscriptionData::Part)conf->part;
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 firstGCI = conf->firstGCI;
-
- SubCoordinatorPtr subPtr;
- c_subCoordinatorPool.getPtr(subPtr, subData);
- ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_START_REQ);
-
- subPtr.p->m_outstandingParticipants.clearWaitingFor(conf->senderNodeId);
-
- if(!subPtr.p->m_outstandingParticipants.done()) return;
- jam();
-
- /*************************
- * All participants ready
- *************************/
- GrepSubStartConf * grepConf = (GrepSubStartConf *) conf;
- grepConf->part = part;
- grepConf->subscriptionId = subId;
- grepConf->subscriptionKey = subKey;
- grepConf->firstGCI = firstGCI;
-
- bool ok = false;
- switch(part) {
- case SubscriptionData::MetaData:
- ok = true;
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_START_CONF, signal,
- GrepSubStartConf::SignalLength, JBB);
-
- /**
- * Send event report
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionInfo,
- GrepEvent::GrepPS_SubStartMetaConf,
- subId, subKey,
- (Uint32)GrepError::GE_NO_ERROR);
-
- c_subCoordinatorPool.release(subPtr);
- break;
- case SubscriptionData::TableData:
- ok = true;
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_START_CONF, signal,
- GrepSubStartConf::SignalLength, JBB);
-
- /**
- * Send event report
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionInfo,
- GrepEvent::GrepPS_SubStartDataConf,
- subId, subKey,
- (Uint32)GrepError::GE_NO_ERROR);
-
-
- c_subCoordinatorPool.release(subPtr);
- break;
- }
- ndbrequire(ok);
-
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSCoord: Recd SUB_START_CONF (subId:%d, subKey:%d, part:%d) "
- "from all slaves",
- subId, subKey, (Uint32)part);
-#endif
-}
-
-/**
- * Handle errors that either occured in:
- * 1) PSCoord
- * or
- * 2) propagated from PSPart
- */
-void
-Grep::PSCoord::execGREP_START_REF(Signal* signal)
-{
- jamEntry();
- GrepStartRef * const ref = (GrepStartRef *)signal->getDataPtr();
- Uint32 subData = ref->senderData;
- GrepError::GE_Code err = (GrepError::GE_Code)ref->err;
- SubscriptionData::Part part = (SubscriptionData::Part)ref->part;
-
- SubCoordinatorPtr subPtr;
- c_runningSubscriptions.getPtr(subPtr, subData);
- sendRefToSS(signal, *subPtr.p, err /*error*/, part);
-}
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: REMOVE SUBSCRIPTION
- * ------------------------------------------------------------------------
- *
- * Remove a subscription at SUMA.
- * Each participant removes its own subscription.
- * We start by deleting the subscription inside the requestor
- * since, we don't know if nodes (REP nodes or DB nodes)
- * have disconnected after we sent out this and
- * if we dont delete the sub in the requestor now,
- * we won't be able to create a new subscription
- **************************************************************************/
-
-/**
- * Request to abort subscription (Sent from SS)
- */
-void
-Grep::PSCoord::execGREP_SUB_REMOVE_REQ(Signal* signal)
-{
- jamEntry();
- GrepSubRemoveReq * const subReq = (GrepSubRemoveReq *)signal->getDataPtr();
- Uint32 subId = subReq->subscriptionId;
- Uint32 subKey = subReq->subscriptionKey;
- BlockReference rep = signal->getSendersBlockRef();
-
- SubCoordinatorPtr subPtr;
- if( !c_subCoordinatorPool.seize(subPtr)) {
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef = rep;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sub.m_outstandingRequest = GSN_GREP_REMOVE_REQ;
- sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL);
- return;
- }
-
-
- prepareOperationRec(subPtr,
- numberToRef(PSREPBLOCKNO, refToNode(rep)),
- subId, subKey,
- GSN_GREP_REMOVE_REQ);
-
- c_runningSubscriptions.add(subPtr);
-
- GrepRemoveReq * req = (GrepRemoveReq *) subReq;
- req->subscriptionId = subPtr.p->m_subscriptionId;
- req->subscriptionKey = subPtr.p->m_subscriptionKey;
- req->senderData = subPtr.p->m_subscriberData;
- req->senderRef = subPtr.p->m_coordinatorRef;
-
- /***************************
- * Send to all participants
- ***************************/
- NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes);
- subPtr.p->m_outstandingParticipants = rg;
- sendSignal(rg,
- GSN_GREP_REMOVE_REQ, signal,
- GrepRemoveReq::SignalLength, JBB);
-}
-
-
-void
-Grep::PSPart::execGREP_REMOVE_REQ(Signal* signal)
-{
- jamEntry();
- GrepRemoveReq * const grepReq = (GrepRemoveReq *) signal->getDataPtr();
- Uint32 subId = grepReq->subscriptionId;
- Uint32 subKey = grepReq->subscriptionKey;
- Uint32 subData = grepReq->senderData;
- Uint32 coordinator = grepReq->senderRef;
-
- Subscription key;
- key.m_subscriptionId = subId;
- key.m_subscriptionKey = subKey;
- SubscriptionPtr subPtr;
-
- if(!c_subscriptions.find(subPtr, key))
- {
- /**
- * The subscription was not found, so it must be deleted.
- * Send CONF back, since it does not exist (thus, it is removed)
- */
- GrepRemoveConf * grepConf = (GrepRemoveConf *)grepReq;
- grepConf->subscriptionKey = subKey;
- grepConf->subscriptionId = subId;
- grepConf->senderData = subData;
- grepConf->senderNodeId = getOwnNodeId();
- sendSignal(coordinator, GSN_GREP_REMOVE_CONF, signal,
- GrepRemoveConf::SignalLength, JBB);
- return;
- }
-
- subPtr.p->m_operationPtrI = subData;
- subPtr.p->m_coordinatorRef = coordinator;
- subPtr.p->m_outstandingRequest = GSN_GREP_REMOVE_REQ;
-
- /**
- * send SUB_REMOVE_REQ to local SUMA
- */
- SubRemoveReq * sumaReq = (SubRemoveReq *) grepReq;
- sumaReq->subscriptionId = subId;
- sumaReq->subscriptionKey = subKey;
- sumaReq->senderData = subPtr.i;
- sendSignal(SUMA_REF, GSN_SUB_REMOVE_REQ, signal,
- SubStartReq::SignalLength, JBB);
-}
-
-
-/**
- * SUB_REMOVE_CONF (from local SUMA)
- */
-void
-Grep::PSPart::execSUB_REMOVE_CONF(Signal* signal)
-{
- jamEntry();
- SubRemoveConf * const conf = (SubRemoveConf *) signal->getDataPtr();
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 subData = conf->subscriberData;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- ndbrequire(subPtr.p->m_subscriptionId == subId);
- ndbrequire(subPtr.p->m_subscriptionKey == subKey);
- subPtr.p->m_outstandingRequest = 0;
- GrepRemoveConf * grepConf = (GrepRemoveConf *)conf;
- grepConf->subscriptionKey = subKey;
- grepConf->subscriptionId = subId;
- grepConf->senderData = subPtr.p->m_operationPtrI;
- grepConf->senderNodeId = getOwnNodeId();
- sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_REMOVE_CONF, signal,
- GrepRemoveConf::SignalLength, JBB);
- c_subscriptions.release(subPtr);
-
-}
-
-
-/**
- * SUB_REMOVE_CONF (from local SUMA)
- */
-void
-Grep::PSPart::execSUB_REMOVE_REF(Signal* signal)
-{
- jamEntry();
- SubRemoveRef * const ref = (SubRemoveRef *)signal->getDataPtr();
- Uint32 subData = ref->subscriberData;
- /* GrepError::GE_Code err = (GrepError::GE_Code)ref->err;*/
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
-
- //sendSubRemoveRef_PSCoord(signal, *subPtr.p, err /*error*/);
-}
-
-
-/**
- * Aborting has been carried out (says Participants)
- */
-void
-Grep::PSCoord::execGREP_REMOVE_CONF(Signal* signal)
-{
- jamEntry();
- GrepRemoveConf * const conf = (GrepRemoveConf *) signal->getDataPtr();
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 senderNodeId = conf->senderNodeId;
- Uint32 subData = conf->senderData;
- SubCoordinatorPtr subPtr;
- c_subCoordinatorPool.getPtr(subPtr, subData);
-
- ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_REMOVE_REQ);
-
- subPtr.p->m_outstandingParticipants.clearWaitingFor(senderNodeId);
-
- if(!subPtr.p->m_outstandingParticipants.done()) {
- jam();
- return;
- }
- jam();
-
- /*************************
- * All participants ready
- *************************/
-
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionInfo,
- GrepEvent::GrepPS_SubRemoveConf,
- subId, subKey,
- GrepError::GE_NO_ERROR);
-
- GrepSubRemoveConf * grepConf = (GrepSubRemoveConf *) conf;
- grepConf->subscriptionId = subId;
- grepConf->subscriptionKey = subKey;
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_REMOVE_CONF, signal,
- GrepSubRemoveConf::SignalLength, JBB);
-
- c_subCoordinatorPool.release(subPtr);
-}
-
-
-
-void
-Grep::PSCoord::execGREP_REMOVE_REF(Signal* signal)
-{
- jamEntry();
- GrepRemoveRef * const ref = (GrepRemoveRef *)signal->getDataPtr();
- Uint32 subData = ref->senderData;
- Uint32 err = ref->err;
- SubCoordinatorPtr subPtr;
-
- /**
- * Get the operationrecord matching subdata and remove it. Subsequent
- * execGREP_REMOVE_REF will simply be ignored at this stage.
- */
- for( c_runningSubscriptions.first(c_subPtr);
- !c_subPtr.isNull(); c_runningSubscriptions.next(c_subPtr)) {
- jam();
- subPtr.i = c_subPtr.curr.i;
- subPtr.p = c_runningSubscriptions.getPtr(subPtr.i);
- if(subData == subPtr.i)
- {
- sendRefToSS(signal, *subPtr.p, (GrepError::GE_Code)err /*error*/);
- c_runningSubscriptions.release(subPtr);
- return;
- }
- }
- return;
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: LOG RECORDS (COMING IN FROM LOCAL SUMA)
- * ------------------------------------------------------------------------
- *
- * After the subscription is started, we get log records from SUMA.
- * Both table data and meta data log records are received.
- *
- * TODO:
- * @todo Changes in meta data is currently not
- * allowed during global replication
- **************************************************************************/
-
-void
-Grep::PSPart::execSUB_META_DATA(Signal* signal)
-{
- jamEntry();
- if(m_recoveryMode) {
- jam();
- return;
- }
- /**
- * METASCAN and METALOG
- */
- SubMetaData * data = (SubMetaData *) signal->getDataPtrSend();
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, data->subscriberData);
-
- /***************************
- * Forward data to REP node
- ***************************/
- sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_META_DATA, signal,
- SubMetaData::SignalLength, JBB);
-#ifdef DEBUG_GREP_SUBSCRIPTION
- ndbout_c("Grep::PSPart: Sent SUB_META_DATA to REP "
- "(TableId: %d, SenderData: %d, GCI: %d)",
- data->tableId, data->senderData, data->gci);
-#endif
-}
-
-/**
- * Receive table data from SUMA and dispatches it to REP node.
- */
-void
-Grep::PSPart::execSUB_TABLE_DATA(Signal* signal)
-{
- jamEntry();
- if(m_recoveryMode) {
- jam();
- return;
- }
- ndbrequire(m_repRef!=0);
-
- if(!assembleFragments(signal)) { jam(); return; }
-
- /**
- * Check if it is SCAN or LOG data that has arrived
- */
- if(signal->getNoOfSections() == 2)
- {
- jam();
- /**
- * DATASCAN - Not marked with GCI, so mark with latest seen GCI
- */
- if(m_firstScanGCI == 1 && m_lastScanGCI == 0) {
- m_firstScanGCI = m_latestSeenGCI;
- m_lastScanGCI = m_latestSeenGCI;
- }
- SubTableData * data = (SubTableData*)signal->getDataPtrSend();
- Uint32 subData = data->senderData;
- data->gci = m_latestSeenGCI;
- data->logType = SubTableData::SCAN;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_TABLE_DATA, signal,
- SubTableData::SignalLength, JBB);
-#ifdef DEBUG_GREP
- ndbout_c("Grep::PSPart: Sent SUB_TABLE_DATA (Scan, GCI: %d)",
- data->gci);
-#endif
- }
- else
- {
- jam();
- /**
- * DATALOG (TRIGGER) - Already marked with GCI
- */
- SubTableData * data = (SubTableData*)signal->getDataPtrSend();
- data->logType = SubTableData::LOG;
- Uint32 subData = data->senderData;
- if (data->gci > m_latestSeenGCI) m_latestSeenGCI = data->gci;
-
- // Reformat to sections and send to replication node.
- LinearSectionPtr ptr[3];
- ptr[0].p = signal->theData + 25;
- ptr[0].sz = data->noOfAttributes;
- ptr[1].p = signal->theData + 25 + MAX_ATTRIBUTES_IN_TABLE;
- ptr[1].sz = data->dataSize;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_TABLE_DATA,
- signal, SubTableData::SignalLength, JBB, ptr, 2);
-#ifdef DEBUG_GREP
- ndbout_c("Grep::PSPart: Sent SUB_TABLE_DATA (Log, GCI: %d)",
- data->gci);
-#endif
- }
-}
-
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: START SYNCHRONIZATION
- * ------------------------------------------------------------------------
- *
- *
- **************************************************************************/
-
-/**
- * Request to start sync (from Rep SS)
- */
-void
-Grep::PSCoord::execGREP_SUB_SYNC_REQ(Signal* signal)
-{
- jamEntry();
- GrepSubSyncReq * const subReq = (GrepSubSyncReq*)signal->getDataPtr();
- SubscriptionData::Part part = (SubscriptionData::Part) subReq->part;
- Uint32 subId = subReq->subscriptionId;
- Uint32 subKey = subReq->subscriptionKey;
- BlockReference rep = signal->getSendersBlockRef();
-
- SubCoordinatorPtr subPtr;
- if( !c_subCoordinatorPool.seize(subPtr)) {
- jam();
- SubCoordinator sub;
- sub.m_subscriberRef = rep;
- sub.m_subscriptionId = 0;
- sub.m_subscriptionKey = 0;
- sub.m_outstandingRequest = GSN_GREP_SYNC_REQ;
- sendRefToSS(signal, sub, GrepError::NOSPACE_IN_POOL);
- return;
- }
-
- prepareOperationRec(subPtr,
- numberToRef(PSREPBLOCKNO, refToNode(rep)),
- subId, subKey,
- GSN_GREP_SYNC_REQ);
-
- GrepSyncReq * req = (GrepSyncReq *)subReq;
- req->subscriptionId = subPtr.p->m_subscriptionId;
- req->subscriptionKey = subPtr.p->m_subscriptionKey;
- req->senderData = subPtr.p->m_subscriberData;
- req->part = (Uint32)part;
-
- /***************************
- * Send to all participants
- ***************************/
- NodeReceiverGroup rg(GREP, m_grep->m_aliveNodes);
- subPtr.p->m_outstandingParticipants = rg;
- sendSignal(rg,
- GSN_GREP_SYNC_REQ, signal, GrepSyncReq::SignalLength, JBB);
-}
-
-
-/**
- * Sync req from Grep::PSCoord to PS particpant
- */
-void
-Grep::PSPart::execGREP_SYNC_REQ(Signal* signal)
-{
- jamEntry();
-
- GrepSyncReq * const grepReq = (GrepSyncReq *) signal->getDataPtr();
- Uint32 part = grepReq->part;
- Uint32 subId = grepReq->subscriptionId;
- Uint32 subKey = grepReq->subscriptionKey;
- Uint32 subData = grepReq->senderData;
-
- Subscription key;
- key.m_subscriptionId = subId;
- key.m_subscriptionKey = subKey;
- SubscriptionPtr subPtr;
- ndbrequire(c_subscriptions.find(subPtr, key));
- subPtr.p->m_operationPtrI = subData;
- subPtr.p->m_outstandingRequest = GSN_GREP_SYNC_REQ;
- /**********************************
- * Send SUB_SYNC_REQ to local SUMA
- **********************************/
- SubSyncReq * sumaReq = (SubSyncReq *)grepReq;
- sumaReq->subscriptionId = subId;
- sumaReq->subscriptionKey = subKey;
- sumaReq->subscriberData = subPtr.i;
- sumaReq->part = part;
- sendSignal(SUMA_REF, GSN_SUB_SYNC_REQ, signal,
- SubSyncReq::SignalLength, JBB);
-}
-
-
-/**
- * SYNC conf from SUMA
- */
-void
-Grep::PSPart::execSUB_SYNC_CONF(Signal* signal)
-{
- jamEntry();
-
- SubSyncConf * const conf = (SubSyncConf *) signal->getDataPtr();
- Uint32 part = conf->part;
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 subData = conf->subscriberData;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
-
- ndbrequire(subPtr.p->m_subscriptionId == subId);
- ndbrequire(subPtr.p->m_subscriptionKey == subKey);
-
- GrepSyncConf * grepConf = (GrepSyncConf *)conf;
- grepConf->senderNodeId = getOwnNodeId();
- grepConf->part = part;
- grepConf->firstGCI = m_firstScanGCI;
- grepConf->lastGCI = m_lastScanGCI;
- grepConf->subscriptionId = subId;
- grepConf->subscriptionKey = subKey;
- grepConf->senderData = subPtr.p->m_operationPtrI;
- sendSignal(subPtr.p->m_coordinatorRef, GSN_GREP_SYNC_CONF, signal,
- GrepSyncConf::SignalLength, JBB);
-
- m_firstScanGCI = 1;
- m_lastScanGCI = 0;
- subPtr.p->m_outstandingRequest = 0;
-}
-
-/**
- * Handle errors that either occured in:
- * 1) PSPart
- * or
- * 2) propagated from local SUMA
- *
- * Propagates REF signal to PSCoord
- */
-void
-Grep::PSPart::execSUB_SYNC_REF(Signal* signal) {
- jamEntry();
- SubSyncRef * const ref = (SubSyncRef *)signal->getDataPtr();
- Uint32 subData = ref->subscriberData;
- GrepError::GE_Code err = (GrepError::GE_Code)ref->err;
- SubscriptionData::Part part = (SubscriptionData::Part)ref->part;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr, subData);
- sendRefToPSCoord(signal, *subPtr.p, err /*error*/ ,part);
- subPtr.p->m_outstandingRequest = 0;
-}
-
-/**
- * Syncing has started... (says PS Participant)
- */
-void
-Grep::PSCoord::execGREP_SYNC_CONF(Signal* signal)
-{
- jamEntry();
-
- GrepSyncConf const * conf = (GrepSyncConf *)signal->getDataPtr();
- Uint32 part = conf->part;
- Uint32 firstGCI = conf->firstGCI;
- Uint32 lastGCI = conf->lastGCI;
- Uint32 subId = conf->subscriptionId;
- Uint32 subKey = conf->subscriptionKey;
- Uint32 subData = conf->senderData;
-
- SubCoordinatorPtr subPtr;
- c_subCoordinatorPool.getPtr(subPtr, subData);
- ndbrequire(subPtr.p->m_outstandingRequest == GSN_GREP_SYNC_REQ);
-
- subPtr.p->m_outstandingParticipants.clearWaitingFor(conf->senderNodeId);
- if(!subPtr.p->m_outstandingParticipants.done()) return;
-
- /**
- * Send event
- */
- GrepEvent::Subscription event;
- if(part == SubscriptionData::MetaData)
- event = GrepEvent::GrepPS_SubSyncMetaConf;
- else
- event = GrepEvent::GrepPS_SubSyncDataConf;
-
- /* @todo Johan: Add firstGCI here. /Lars */
- m_grep->sendEventRep(signal, NDB_LE_GrepSubscriptionInfo,
- event, subId, subKey,
- (Uint32)GrepError::GE_NO_ERROR,
- lastGCI);
-
- /*************************
- * All participants ready
- *************************/
- GrepSubSyncConf * grepConf = (GrepSubSyncConf *)conf;
- grepConf->part = part;
- grepConf->firstGCI = firstGCI;
- grepConf->lastGCI = lastGCI;
- grepConf->subscriptionId = subId;
- grepConf->subscriptionKey = subKey;
-
- sendSignal(subPtr.p->m_subscriberRef, GSN_GREP_SUB_SYNC_CONF, signal,
- GrepSubSyncConf::SignalLength, JBB);
- c_subCoordinatorPool.release(subPtr);
-}
-
-/**
- * Handle errors that either occured in:
- * 1) PSCoord
- * or
- * 2) propagated from PSPart
- */
-void
-Grep::PSCoord::execGREP_SYNC_REF(Signal* signal) {
- jamEntry();
- GrepSyncRef * const ref = (GrepSyncRef *)signal->getDataPtr();
- Uint32 subData = ref->senderData;
- SubscriptionData::Part part = (SubscriptionData::Part)ref->part;
- GrepError::GE_Code err = (GrepError::GE_Code)ref->err;
- SubCoordinatorPtr subPtr;
- c_runningSubscriptions.getPtr(subPtr, subData);
- sendRefToSS(signal, *subPtr.p, err /*error*/, part);
-}
-
-
-
-void
-Grep::PSCoord::sendRefToSS(Signal * signal,
- SubCoordinator sub,
- GrepError::GE_Code err,
- SubscriptionData::Part part) {
- /**
-
- GrepCreateRef * ref = (GrepCreateRef*)signal->getDataPtrSend();
- ref->senderData = sub.m_subscriberData;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->err = err;
- sendSignal(sub.m_coordinatorRef, GSN_GREP_CREATE_REF, signal,
- GrepCreateRef::SignalLength, JBB);
-*/
-
- jam();
- GrepEvent::Subscription event;
- switch(sub.m_outstandingRequest) {
- case GSN_GREP_CREATE_SUBID_REQ:
- {
- jam();
- CreateSubscriptionIdRef * ref =
- (CreateSubscriptionIdRef*)signal->getDataPtrSend();
- ref->err = (Uint32)err;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- sendSignal(sub.m_subscriberRef,
- GSN_GREP_CREATE_SUBID_REF,
- signal,
- CreateSubscriptionIdRef::SignalLength,
- JBB);
- event = GrepEvent::GrepPS_CreateSubIdRef;
- }
- break;
- case GSN_GREP_CREATE_REQ:
- {
- jam();
- GrepSubCreateRef * ref = (GrepSubCreateRef*)signal->getDataPtrSend();
- ref->err = (Uint32)err;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- sendSignal(sub.m_subscriberRef, GSN_GREP_SUB_CREATE_REF, signal,
- GrepSubCreateRef::SignalLength, JBB);
- event = GrepEvent::GrepPS_SubCreateRef;
- }
- break;
- case GSN_GREP_SYNC_REQ:
- {
- jam();
- GrepSubSyncRef * ref = (GrepSubSyncRef*)signal->getDataPtrSend();
- ref->err = (Uint32)err;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->part = (SubscriptionData::Part) part;
- sendSignal(sub.m_subscriberRef,
- GSN_GREP_SUB_SYNC_REF,
- signal,
- GrepSubSyncRef::SignalLength,
- JBB);
- if(part == SubscriptionData::MetaData)
- event = GrepEvent::GrepPS_SubSyncMetaRef;
- else
- event = GrepEvent::GrepPS_SubSyncDataRef;
- }
- break;
- case GSN_GREP_START_REQ:
- {
- jam();
- GrepSubStartRef * ref = (GrepSubStartRef*)signal->getDataPtrSend();
- ref->err = (Uint32)err;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
-
- sendSignal(sub.m_subscriberRef, GSN_GREP_SUB_START_REF,
- signal, GrepSubStartRef::SignalLength, JBB);
- if(part == SubscriptionData::MetaData)
- event = GrepEvent::GrepPS_SubStartMetaRef;
- else
- event = GrepEvent::GrepPS_SubStartDataRef;
- /**
- * Send event report
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionAlert,
- event,
- sub.m_subscriptionId,
- sub.m_subscriptionKey,
- (Uint32)err);
- }
- break;
- case GSN_GREP_REMOVE_REQ:
- {
- jam();
- GrepSubRemoveRef * ref = (GrepSubRemoveRef*)signal->getDataPtrSend();
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->err = (Uint32)err;
-
- sendSignal(sub.m_subscriberRef,
- GSN_GREP_SUB_REMOVE_REF,
- signal,
- GrepSubRemoveRef::SignalLength,
- JBB);
-
- event = GrepEvent::GrepPS_SubRemoveRef;
- }
- break;
- default:
- ndbrequire(false);
- event= GrepEvent::Rep_Disconnect; // remove compiler warning
- }
- /**
- * Finally, send an event.
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionAlert,
- event,
- sub.m_subscriptionId,
- sub.m_subscriptionKey,
- err);
-
-}
-
-
-void
-Grep::PSPart::sendRefToPSCoord(Signal * signal,
- Subscription sub,
- GrepError::GE_Code err,
- SubscriptionData::Part part) {
-
- jam();
- GrepEvent::Subscription event;
- switch(sub.m_outstandingRequest) {
-
- case GSN_GREP_CREATE_REQ:
- {
- GrepCreateRef * ref = (GrepCreateRef*)signal->getDataPtrSend();
- ref->senderData = sub.m_subscriberData;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->err = err;
- sendSignal(sub.m_coordinatorRef, GSN_GREP_CREATE_REF, signal,
- GrepCreateRef::SignalLength, JBB);
-
- event = GrepEvent::GrepPS_SubCreateRef;
- }
- break;
- case GSN_GREP_SYNC_REQ:
- {
- GrepSyncRef * ref = (GrepSyncRef*)signal->getDataPtrSend();
- ref->senderData = sub.m_subscriberData;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->part = part;
- ref->err = err;
- sendSignal(sub.m_coordinatorRef,
- GSN_GREP_SYNC_REF, signal,
- GrepSyncRef::SignalLength, JBB);
- if(part == SubscriptionData::MetaData)
- event = GrepEvent::GrepPS_SubSyncMetaRef;
- else
- event = GrepEvent::GrepPS_SubSyncDataRef;
- }
- break;
- case GSN_GREP_START_REQ:
- {
- jam();
- GrepStartRef * ref = (GrepStartRef*)signal->getDataPtrSend();
- ref->senderData = sub.m_subscriberData;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->part = (Uint32) part;
- ref->err = err;
- sendSignal(sub.m_coordinatorRef, GSN_GREP_START_REF, signal,
- GrepStartRef::SignalLength, JBB);
- if(part == SubscriptionData::MetaData)
- event = GrepEvent::GrepPS_SubStartMetaRef;
- else
- event = GrepEvent::GrepPS_SubStartDataRef;
- }
- break;
-
- case GSN_GREP_REMOVE_REQ:
- {
- jamEntry();
- GrepRemoveRef * ref = (GrepRemoveRef*)signal->getDataPtrSend();
- ref->senderData = sub.m_operationPtrI;
- ref->subscriptionId = sub.m_subscriptionId;
- ref->subscriptionKey = sub.m_subscriptionKey;
- ref->err = err;
- sendSignal(sub.m_coordinatorRef, GSN_GREP_REMOVE_REF, signal,
- GrepCreateRef::SignalLength, JBB);
-
- }
- break;
- default:
- ndbrequire(false);
- event= GrepEvent::Rep_Disconnect; // remove compiler warning
- }
-
- /**
- * Finally, send an event.
- */
- m_grep->sendEventRep(signal,
- NDB_LE_GrepSubscriptionAlert,
- event,
- sub.m_subscriptionId,
- sub.m_subscriptionKey,
- err);
-
-}
-
-/**************************************************************************
- * ------------------------------------------------------------------------
- * MODULE: GREP PS Coordinator GCP
- * ------------------------------------------------------------------------
- *
- *
- **************************************************************************/
-
-void
-Grep::PSPart::execSUB_GCP_COMPLETE_REP(Signal* signal)
-{
- jamEntry();
- if(m_recoveryMode) {
- jam();
- return;
- }
- SubGcpCompleteRep * rep = (SubGcpCompleteRep *)signal->getDataPtrSend();
- rep->senderRef = reference();
-
- if (rep->gci > m_latestSeenGCI) m_latestSeenGCI = rep->gci;
- SubscriptionPtr subPtr;
- c_subscriptions.first(c_subPtr);
- for(; !c_subPtr.isNull(); c_subscriptions.next(c_subPtr)) {
-
- subPtr.i = c_subPtr.curr.i;
- subPtr.p = c_subscriptions.getPtr(subPtr.i);
- sendSignal(subPtr.p->m_subscriberRef, GSN_SUB_GCP_COMPLETE_REP, signal,
- SubGcpCompleteRep::SignalLength, JBB);
- }
-
-#ifdef DEBUG_GREP
- ndbout_c("Grep::PSPart: Recd SUB_GCP_COMPLETE_REP "
- "(GCI: %d, nodeId: %d) from SUMA",
- rep->gci, refToNode(rep->senderRef));
-#endif
-}
-
-
-void
-Grep::PSPart::execSUB_SYNC_CONTINUE_REQ(Signal* signal)
-{
- jamEntry();
- SubSyncContinueReq * const req = (SubSyncContinueReq*)signal->getDataPtr();
- Uint32 subData = req->subscriberData;
-
- SubscriptionPtr subPtr;
- c_subscriptions.getPtr(subPtr,subData);
-
- /**
- * @todo Figure out how to control how much data we can receive?
- */
- SubSyncContinueConf * conf = (SubSyncContinueConf*)req;
- conf->subscriptionId = subPtr.p->m_subscriptionId;
- conf->subscriptionKey = subPtr.p->m_subscriptionKey;
- sendSignal(SUMA_REF, GSN_SUB_SYNC_CONTINUE_CONF, signal,
- SubSyncContinueConf::SignalLength, JBB);
-}
-
-void
-Grep::sendEventRep(Signal * signal,
- Ndb_logevent_type type,
- GrepEvent::Subscription event,
- Uint32 subId,
- Uint32 subKey,
- Uint32 err,
- Uint32 other) {
- jam();
- signal->theData[0] = type;
- signal->theData[1] = event;
- signal->theData[2] = subId;
- signal->theData[3] = subKey;
- signal->theData[4] = err;
-
- if(other==0)
- sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 5 ,JBB);
- else {
- signal->theData[5] = other;
- sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6 ,JBB);
- }
-}
diff --git a/storage/ndb/src/kernel/blocks/grep/Grep.hpp b/storage/ndb/src/kernel/blocks/grep/Grep.hpp
deleted file mode 100644
index a14143294e1..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/Grep.hpp
+++ /dev/null
@@ -1,535 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#ifndef GREP_HPP
-#define GREP_HPP
-
-#include <ndb_limits.h>
-#include <SimulatedBlock.hpp>
-
-#include <NodeBitmask.hpp>
-#include <SignalCounter.hpp>
-#include <SLList.hpp>
-
-#include <DLList.hpp>
-
-#include <GrepError.hpp>
-#include <GrepEvent.hpp>
-
-#include <signaldata/EventReport.hpp>
-#include <signaldata/SumaImpl.hpp>
-
-
-/**
- * Module in block (Should be placed elsewhere)
- */
-class BlockComponent {
-public:
- BlockComponent(SimulatedBlock *);
- BlockReference reference() { return m_sb->reference(); };
- BlockNumber number() { return m_sb->number(); };
-
- void sendSignal(NodeReceiverGroup rg,
- GlobalSignalNumber gsn,
- Signal* signal,
- Uint32 length,
- JobBufferLevel jbuf ) const {
- m_sb->sendSignal(rg, gsn, signal, length, jbuf);
- }
-
- void sendSignal(BlockReference ref,
- GlobalSignalNumber gsn,
- Signal* signal,
- Uint32 length,
- JobBufferLevel jbuf ) const {
- m_sb->sendSignal(ref, gsn, signal, length, jbuf);
- }
-
- void sendSignal(BlockReference ref,
- GlobalSignalNumber gsn,
- Signal* signal,
- Uint32 length,
- JobBufferLevel jbuf,
- LinearSectionPtr ptr[3],
- Uint32 noOfSections) const {
- m_sb->sendSignal(ref, gsn, signal, length, jbuf, ptr, noOfSections);
- }
-
- void sendSignalWithDelay(BlockReference ref,
- GlobalSignalNumber gsn,
- Signal* signal,
- Uint32 delayInMilliSeconds,
- Uint32 length) const {
-
- m_sb->sendSignalWithDelay(ref, gsn, signal, delayInMilliSeconds, length);
- }
-
- NodeId getOwnNodeId() const {
- return m_sb->getOwnNodeId();
- }
-
- bool assembleFragments(Signal * signal) {
- return m_sb->assembleFragments(signal);
- }
-
- void progError(int line, int err_code, const char* extra) {
- m_sb->progError(line, err_code, extra);
- }
-
-private:
- SimulatedBlock * m_sb;
-};
-
-
-
-/**
- * Participant of GREP Protocols (not necessarily a protocol coordinator)
- *
- * This object is only used on primary system
- */
-#if 0
-class GrepParticipant : public SimulatedBlock
-{
-protected:
- GrepParticipant(const Configuration & conf);
- virtual ~GrepParticipant();
- BLOCK_DEFINES(GrepParticipant);
-
-protected:
- /***************************************************************************
- * SUMA Signal Interface
- ***************************************************************************/
- void execSUB_CREATE_CONF(Signal*);
- void execSUB_STARTCONF(Signal*);
- void execSUB_REMOVE_CONF(Signal*);
-
- void execSUB_META_DATA(Signal*);
- void execSUB_TABLE_DATA(Signal*);
-
- void execSUB_SYNC_CONF(Signal*);
-
- void execSUB_GCP_COMPLETE_REP(Signal*);
- void execSUB_SYNC_CONTINUE_REQ(Signal*);
-
- /***************************************************************************
- * GREP Coordinator Signal Interface
- ***************************************************************************/
- void execGREP_CREATE_REQ(Signal*);
- void execGREP_START_REQ(Signal*);
- void execGREP_SYNC_REQ(Signal*);
- void execGREP_REMOVE_REQ(Signal*);
-
-
-protected:
- BlockReference m_repRef; ///< Replication node (only one rep node per grep)
-
-private:
- BlockReference m_coordinator;
- Uint32 m_latestSeenGCI;
-};
-#endif
-
-
-/**
- * GREP Coordinator
- */
-class Grep : public SimulatedBlock //GrepParticipant
-{
- BLOCK_DEFINES(Grep);
-
-public:
- Grep(const Configuration & conf);
- virtual ~Grep();
-
-private:
- /***************************************************************************
- * General Signal Recivers
- ***************************************************************************/
- void execSTTOR(Signal*);
- void sendSTTORRY(Signal*);
- void execNDB_STTOR(Signal*);
- void execDUMP_STATE_ORD(Signal*);
- void execREAD_NODESCONF(Signal*);
- void execNODE_FAILREP(Signal*);
- void execINCL_NODEREQ(Signal*);
- void execGREP_REQ(Signal*);
- void execAPI_FAILREQ(Signal*);
- /**
- * Forwarded to PSCoord
- */
- //CONF
- void fwdGREP_CREATE_CONF(Signal* s) {
- pscoord.execGREP_CREATE_CONF(s); };
- void fwdGREP_START_CONF(Signal* s) {
- pscoord.execGREP_START_CONF(s); };
- void fwdGREP_SYNC_CONF(Signal* s) {
- pscoord.execGREP_SYNC_CONF(s); };
- void fwdGREP_REMOVE_CONF(Signal* s) {
- pscoord.execGREP_REMOVE_CONF(s); };
- void fwdCREATE_SUBID_CONF(Signal* s) {
- pscoord.execCREATE_SUBID_CONF(s); };
-
- //REF
-
- void fwdGREP_CREATE_REF(Signal* s) {
- pscoord.execGREP_CREATE_REF(s); };
- void fwdGREP_START_REF(Signal* s) {
- pscoord.execGREP_START_REF(s); };
- void fwdGREP_SYNC_REF(Signal* s) {
- pscoord.execGREP_SYNC_REF(s); };
-
- void fwdGREP_REMOVE_REF(Signal* s) {
- pscoord.execGREP_REMOVE_REF(s); };
-
- void fwdCREATE_SUBID_REF(Signal* s) {
- pscoord.execCREATE_SUBID_REF(s); };
-
- //REQ
- void fwdGREP_SUB_CREATE_REQ(Signal* s) {
- pscoord.execGREP_SUB_CREATE_REQ(s); };
- void fwdGREP_SUB_START_REQ(Signal* s) {
- pscoord.execGREP_SUB_START_REQ(s); };
- void fwdGREP_SUB_SYNC_REQ(Signal* s) {
- pscoord.execGREP_SUB_SYNC_REQ(s); };
- void fwdGREP_SUB_REMOVE_REQ(Signal* s) {
- pscoord.execGREP_SUB_REMOVE_REQ(s); };
- void fwdGREP_CREATE_SUBID_REQ(Signal* s) {
- pscoord.execGREP_CREATE_SUBID_REQ(s); };
-
- /**
- * Forwarded to PSPart
- */
-
- void fwdSTART_ME(Signal* s){
- pspart.execSTART_ME(s);
- };
- void fwdGREP_ADD_SUB_REQ(Signal* s){
- pspart.execGREP_ADD_SUB_REQ(s);
- };
- void fwdGREP_ADD_SUB_REF(Signal* s){
- pspart.execGREP_ADD_SUB_REF(s);
- };
- void fwdGREP_ADD_SUB_CONF(Signal* s){
- pspart.execGREP_ADD_SUB_CONF(s);
- };
-
- //CONF
- void fwdSUB_CREATE_CONF(Signal* s) {
- pspart.execSUB_CREATE_CONF(s); };
- void fwdSUB_START_CONF(Signal* s) {
- pspart.execSUB_START_CONF(s); };
- void fwdSUB_REMOVE_CONF(Signal* s) {
- pspart.execSUB_REMOVE_CONF(s); };
- void fwdSUB_SYNC_CONF(Signal* s) {
- pspart.execSUB_SYNC_CONF(s); };
-
- //REF
-
- void fwdSUB_CREATE_REF(Signal* s) {
- pspart.execSUB_CREATE_REF(s); };
- void fwdSUB_START_REF(Signal* s) {
- pspart.execSUB_START_REF(s); };
- void fwdSUB_REMOVE_REF(Signal* s) {
- pspart.execSUB_REMOVE_REF(s); };
- void fwdSUB_SYNC_REF(Signal* s) {
- pspart.execSUB_SYNC_REF(s); };
-
- //REQ
- void fwdSUB_SYNC_CONTINUE_REQ(Signal* s) {
- pspart.execSUB_SYNC_CONTINUE_REQ(s); };
- void fwdGREP_CREATE_REQ(Signal* s) {
- pspart.execGREP_CREATE_REQ(s); };
- void fwdGREP_START_REQ(Signal* s) {
- pspart.execGREP_START_REQ(s); };
- void fwdGREP_SYNC_REQ(Signal* s) {
- pspart.execGREP_SYNC_REQ(s); };
- void fwdGREP_REMOVE_REQ(Signal* s) {
- pspart.execGREP_REMOVE_REQ(s); };
-
- void fwdSUB_META_DATA(Signal* s) {
- pspart.execSUB_META_DATA(s); };
- void fwdSUB_TABLE_DATA(Signal* s) {
- pspart.execSUB_TABLE_DATA(s); };
-
- void fwdSUB_GCP_COMPLETE_REP(Signal* s) {
- pspart.execSUB_GCP_COMPLETE_REP(s); };
-
- void sendEventRep(Signal * signal,
- Ndb_logevent_type type,
- GrepEvent::Subscription event,
- Uint32 subId,
- Uint32 subKey,
- Uint32 err,
- Uint32 gci=0);
-
- void getNodeGroupMembers(Signal* signal);
-
-
- /***************************************************************************
- * Block Data
- ***************************************************************************/
- struct Node {
- Uint32 nodeId;
- Uint32 alive;
- Uint32 nextList;
- union { Uint32 prevList; Uint32 nextPool; };
- };
- typedef Ptr<Node> NodePtr;
-
- NodeId m_masterNodeId;
- SLList<Node> m_nodes;
- NdbNodeBitmask m_aliveNodes;
- ArrayPool<Node> m_nodePool;
-
- /**
- * for all Suma's to keep track of other Suma's in Node group
- */
- Uint32 c_nodeGroup;
- Uint32 c_noNodesInGroup;
- Uint32 c_idInNodeGroup;
- NodeId c_nodesInGroup[4];
-
-
-public:
- /***************************************************************************
- * GREP PS Coordinator
- ***************************************************************************/
- class PSCoord : public BlockComponent {
-
- private:
-
- struct SubCoordinator {
- Uint32 m_subscriberRef;
- Uint32 m_subscriberData;
- Uint32 m_coordinatorRef;
- Uint32 m_subscriptionId;
- Uint32 m_subscriptionKey;
- Uint32 m_subscriptionType;
- NdbNodeBitmask m_participants;
- Uint32 m_outstandingRequest;
- SignalCounter m_outstandingParticipants;
-
- Uint32 nextHash;
- union { Uint32 prevHash; Uint32 nextPool; };
-
- Uint32 hashValue() const {
- return m_subscriptionId + m_subscriptionKey;
- }
-
- bool equal(const SubCoordinator & s) const {
- return
- m_subscriptionId == s.m_subscriptionId &&
- m_subscriptionKey == s.m_subscriptionKey;
- }
-
- };
-
- typedef Ptr<SubCoordinator> SubCoordinatorPtr;
- ArrayPool<SubCoordinator> c_subCoordinatorPool;
- DLHashTable<SubCoordinator>::Iterator c_subPtr;
- DLHashTable<SubCoordinator> c_runningSubscriptions;
-
- void prepareOperationRec(SubCoordinatorPtr ptr,
- BlockReference subscriber,
- Uint32 subId,
- Uint32 subKey,
- Uint32 request);
-
- public:
- PSCoord(class Grep *);
-
- void execGREP_CREATE_CONF(Signal*);
- void execGREP_START_CONF(Signal*);
- void execGREP_SYNC_CONF(Signal*);
- void execGREP_REMOVE_CONF(Signal*);
-
- void execGREP_CREATE_REF(Signal*);
- void execGREP_START_REF(Signal*);
- void execGREP_SYNC_REF(Signal*);
- void execGREP_REMOVE_REF(Signal*);
-
-
- void execCREATE_SUBID_CONF(Signal*); //comes from SUMA
- void execGREP_CREATE_SUBID_REQ(Signal*);
-
- void execGREP_SUB_CREATE_REQ(Signal*);
- void execGREP_SUB_START_REQ(Signal*);
- void execGREP_SUB_SYNC_REQ(Signal*);
- void execGREP_SUB_REMOVE_REQ(Signal*);
-
-
-
- void execCREATE_SUBID_REF(Signal*);
-
-
-
- void sendCreateSubIdRef_SS(Signal * signal,
- Uint32 subId,
- Uint32 subKey,
- BlockReference to,
- GrepError::GE_Code err);
-
-
- void sendSubRemoveRef_SS(Signal * signal,
- SubCoordinator sub,
- GrepError::GE_Code err);
-
- void sendRefToSS(Signal * signal,
- SubCoordinator sub,
- GrepError::GE_Code err,
- SubscriptionData::Part part = (SubscriptionData::Part)0);
-
- void setRepRef(BlockReference rr) { m_repRef = rr; };
- //void setAliveNodes(NdbNodeBitmask an) { m_aliveNodes = an; };
-
- BlockReference m_repRef; ///< Rep node (only one rep node per grep)
- // NdbNodeBitmask m_aliveNodes;
-
- Uint32 m_outstandingRequest;
- SignalCounter m_outstandingParticipants;
-
- Grep * m_grep;
- } pscoord;
- friend class PSCoord;
-
- /***************************************************************************
- * GREP PS Participant
- ***************************************************************************
- * Participant of GREP Protocols (not necessarily a protocol coordinator)
- *
- * This object is only used on primary system
- ***************************************************************************/
- class PSPart: public BlockComponent
- {
- //protected:
- //GrepParticipant(const Configuration & conf);
- //virtual ~GrepParticipant();
- //BLOCK_DEFINES(GrepParticipant);
-
- struct Subscription {
- Uint32 m_subscriberRef;
- Uint32 m_subscriberData;
- Uint32 m_subscriptionId;
- Uint32 m_subscriptionKey;
- Uint32 m_subscriptionType;
- Uint32 m_coordinatorRef;
- Uint32 m_outstandingRequest;
- Uint32 m_operationPtrI;
- Uint32 nextHash;
- union { Uint32 prevHash; Uint32 nextPool; };
-
- Uint32 hashValue() const {
- return m_subscriptionId + m_subscriptionKey;
- }
-
- bool equal(const Subscription & s) const {
- return
- m_subscriptionId == s.m_subscriptionId &&
- m_subscriptionKey == s.m_subscriptionKey;
- }
-
- };
- typedef Ptr<Subscription> SubscriptionPtr;
-
- DLHashTable<Subscription> c_subscriptions;
- DLHashTable<Subscription>::Iterator c_subPtr;
- ArrayPool<Subscription> c_subscriptionPool;
-
- public:
- PSPart(class Grep *);
-
-
- //protected:
- /*************************************************************************
- * SUMA Signal Interface
- *************************************************************************/
- void execSUB_CREATE_CONF(Signal*);
- void execSUB_START_CONF(Signal*);
- void execSUB_SYNC_CONF(Signal*);
- void execSUB_REMOVE_CONF(Signal*);
-
- void execSUB_CREATE_REF(Signal*);
- void execSUB_START_REF(Signal*);
- void execSUB_SYNC_REF(Signal*);
- void execSUB_REMOVE_REF(Signal*);
-
-
- void execSUB_META_DATA(Signal*);
- void execSUB_TABLE_DATA(Signal*);
-
-
- void execSUB_GCP_COMPLETE_REP(Signal*);
- void execSUB_SYNC_CONTINUE_REQ(Signal*);
-
- /*************************************************************************
- * GREP Coordinator Signal Interface
- *************************************************************************/
- void execGREP_CREATE_REQ(Signal*);
- void execGREP_START_REQ(Signal*);
- void execGREP_SYNC_REQ(Signal*);
- void execGREP_REMOVE_REQ(Signal*);
-
- /**
- * NR/NF signals
- */
- void execSTART_ME(Signal *);
- void execGREP_ADD_SUB_REQ(Signal *);
- void execGREP_ADD_SUB_REF(Signal *);
- void execGREP_ADD_SUB_CONF(Signal *);
-
- /*************************************************************************
- * GREP Coordinator error handling interface
- *************************************************************************/
-
- void sendRefToPSCoord(Signal * signal,
- Subscription sub,
- GrepError::GE_Code err,
- SubscriptionData::Part part = (SubscriptionData::Part)0);
-
- //protected:
- BlockReference m_repRef; ///< Replication node
- ///< (only one rep node per grep)
- bool m_recoveryMode;
-
- private:
- BlockReference m_coordinator;
- Uint32 m_firstScanGCI;
- Uint32 m_lastScanGCI;
- Uint32 m_latestSeenGCI;
- Grep * m_grep;
- } pspart;
- friend class PSPart;
-
- /***************************************************************************
- * AddRecSignal Stuff (should maybe be gerneralized)
- ***************************************************************************/
- typedef void (Grep::* ExecSignalLocal1) (Signal* signal);
- typedef void (Grep::PSCoord::* ExecSignalLocal2) (Signal* signal);
- typedef void (Grep::PSPart::* ExecSignalLocal4) (Signal* signal);
-};
-
-
-/*************************************************************************
- * Requestor
- *
- * The following methods are callbacks (registered functions)
- * for the Requestor. The Requestor calls these when it needs
- * something to be done.
- *************************************************************************/
-void startSubscription(void * cbObj, Signal*, int type);
-void scanSubscription(void * cbObj, Signal*, int type);
-
-#endif
diff --git a/storage/ndb/src/kernel/blocks/grep/GrepInit.cpp b/storage/ndb/src/kernel/blocks/grep/GrepInit.cpp
deleted file mode 100644
index d764fb1f473..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/GrepInit.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "Grep.hpp"
-#include <Properties.hpp>
-#include <Configuration.hpp>
-
-/*****************************************************************************
- * Grep Participant
- *****************************************************************************/
-#if 0
-GrepParticipant::GrepParticipant(const Configuration & conf) :
- SimulatedBlock(GREP, conf)
-{
- BLOCK_CONSTRUCTOR(Grep);
- //m_repRef = 0;
- m_latestSeenGCI = 0;
-}
-
-GrepParticipant::~GrepParticipant()
-{
-}
-
-BLOCK_FUNCTIONS(GrepParticipant);
-#endif
-
-/*****************************************************************************
- * Grep Coordinator
- *****************************************************************************/
-Grep::Grep(const Configuration & conf) :
- // GrepParticipant(conf),
- SimulatedBlock(GREP, conf),
- m_nodes(m_nodePool),
- pscoord(this),
- pspart(this)
-{
- m_nodePool.setSize(MAX_NDB_NODES);
- m_masterNodeId = getOwnNodeId();
-
- /***************************************************************************
- * General Signals
- ***************************************************************************/
- addRecSignal(GSN_STTOR, &Grep::execSTTOR);
- addRecSignal(GSN_NDB_STTOR, &Grep::execNDB_STTOR);
- addRecSignal(GSN_DUMP_STATE_ORD, &Grep::execDUMP_STATE_ORD);
- addRecSignal(GSN_READ_NODESCONF, &Grep::execREAD_NODESCONF);
- addRecSignal(GSN_NODE_FAILREP, &Grep::execNODE_FAILREP);
- addRecSignal(GSN_INCL_NODEREQ, &Grep::execINCL_NODEREQ);
-
- addRecSignal(GSN_GREP_REQ, &Grep::execGREP_REQ);
- addRecSignal(GSN_API_FAILREQ, &Grep::execAPI_FAILREQ);
-
-
- /***************************************************************************
- * Grep::PSCoord Signal Interface
- ***************************************************************************/
- /**
- * From Grep::PSPart
- */
- addRecSignal(GSN_GREP_CREATE_CONF, &Grep::fwdGREP_CREATE_CONF);
- addRecSignal(GSN_GREP_START_CONF, &Grep::fwdGREP_START_CONF);
- addRecSignal(GSN_GREP_SYNC_CONF, &Grep::fwdGREP_SYNC_CONF);
- addRecSignal(GSN_GREP_REMOVE_CONF, &Grep::fwdGREP_REMOVE_CONF);
-
- addRecSignal(GSN_GREP_CREATE_REF, &Grep::fwdGREP_CREATE_REF);
- addRecSignal(GSN_GREP_START_REF, &Grep::fwdGREP_START_REF);
- addRecSignal(GSN_GREP_REMOVE_REF, &Grep::fwdGREP_REMOVE_REF);
-
- /**
- * From Grep::SSCoord to Grep::PSCoord
- */
- addRecSignal(GSN_GREP_SUB_START_REQ, &Grep::fwdGREP_SUB_START_REQ);
- addRecSignal(GSN_GREP_SUB_CREATE_REQ, &Grep::fwdGREP_SUB_CREATE_REQ);
- addRecSignal(GSN_GREP_SUB_SYNC_REQ, &Grep::fwdGREP_SUB_SYNC_REQ);
- addRecSignal(GSN_GREP_SUB_REMOVE_REQ, &Grep::fwdGREP_SUB_REMOVE_REQ);
- addRecSignal(GSN_GREP_CREATE_SUBID_REQ, &Grep::fwdGREP_CREATE_SUBID_REQ);
-
- /****************************************************************************
- * PSPart
- ***************************************************************************/
- /**
- * From SUMA to GREP PS Participant. If suma is not a coodinator
- */
- addRecSignal(GSN_SUB_START_CONF, &Grep::fwdSUB_START_CONF);
- addRecSignal(GSN_SUB_CREATE_CONF, &Grep::fwdSUB_CREATE_CONF);
- addRecSignal(GSN_SUB_SYNC_CONF, &Grep::fwdSUB_SYNC_CONF);
- addRecSignal(GSN_SUB_REMOVE_CONF, &Grep::fwdSUB_REMOVE_CONF);
- addRecSignal(GSN_SUB_CREATE_REF, &Grep::fwdSUB_CREATE_REF);
- addRecSignal(GSN_SUB_START_REF, &Grep::fwdSUB_START_REF);
- addRecSignal(GSN_SUB_SYNC_REF, &Grep::fwdSUB_SYNC_REF);
- addRecSignal(GSN_SUB_REMOVE_REF, &Grep::fwdSUB_REMOVE_REF);
-
- addRecSignal(GSN_SUB_SYNC_CONTINUE_REQ,
- &Grep::fwdSUB_SYNC_CONTINUE_REQ);
-
- /**
- * From Suma to Grep::PSPart. Data signals.
- */
- addRecSignal(GSN_SUB_META_DATA, &Grep::fwdSUB_META_DATA);
- addRecSignal(GSN_SUB_TABLE_DATA, &Grep::fwdSUB_TABLE_DATA);
- addRecSignal(GSN_SUB_GCP_COMPLETE_REP, &Grep::fwdSUB_GCP_COMPLETE_REP);
-
- /**
- * From Grep::PSCoord to Grep::PSPart
- */
- addRecSignal(GSN_GREP_CREATE_REQ, &Grep::fwdGREP_CREATE_REQ);
- addRecSignal(GSN_GREP_START_REQ, &Grep::fwdGREP_START_REQ);
- addRecSignal(GSN_GREP_REMOVE_REQ, &Grep::fwdGREP_REMOVE_REQ);
- addRecSignal(GSN_GREP_SYNC_REQ, &Grep::fwdGREP_SYNC_REQ);
- addRecSignal(GSN_CREATE_SUBID_CONF, &Grep::fwdCREATE_SUBID_CONF);
- addRecSignal(GSN_GREP_START_ME, &Grep::fwdSTART_ME);
- addRecSignal(GSN_GREP_ADD_SUB_REQ, &Grep::fwdGREP_ADD_SUB_REQ);
- addRecSignal(GSN_GREP_ADD_SUB_REF, &Grep::fwdGREP_ADD_SUB_REF);
- addRecSignal(GSN_GREP_ADD_SUB_CONF, &Grep::fwdGREP_ADD_SUB_CONF);
-}
-
-Grep::~Grep()
-{
-}
-
-BLOCK_FUNCTIONS(Grep)
-
-Grep::PSPart::PSPart(Grep * sb) :
- BlockComponent(sb),
- c_subscriptions(c_subscriptionPool)
-{
- m_grep = sb;
-
- m_firstScanGCI = 1; // Empty interval = [1,0]
- m_lastScanGCI = 0;
-
- m_latestSeenGCI = 0;
-
- c_subscriptions.setSize(10);
- c_subscriptionPool.setSize(10);
-}
-
-Grep::PSCoord::PSCoord(Grep * sb) :
- BlockComponent(sb),
- c_runningSubscriptions(c_subCoordinatorPool)
-{
- m_grep = sb;
- c_runningSubscriptions.setSize(10);
- c_subCoordinatorPool.setSize(2);
-}
-
-//BLOCK_FUNCTIONS(Grep::PSCoord);
-
-BlockComponent::BlockComponent(SimulatedBlock * sb) {
- m_sb = sb;
-}
diff --git a/storage/ndb/src/kernel/blocks/grep/Makefile.am b/storage/ndb/src/kernel/blocks/grep/Makefile.am
deleted file mode 100644
index 92d75d002a5..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-noinst_LIBRARIES = libgrep.a
-
-libgrep_a_SOURCES = Grep.cpp GrepInit.cpp
-
-include $(top_srcdir)/storage/ndb/config/common.mk.am
-include $(top_srcdir)/storage/ndb/config/type_kernel.mk.am
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
-
-windoze-dsp: libgrep.dsp
-
-libgrep.dsp: Makefile \
- $(top_srcdir)/storage/ndb/config/win-lib.am \
- $(top_srcdir)/storage/ndb/config/win-name \
- $(top_srcdir)/storage/ndb/config/win-includes \
- $(top_srcdir)/storage/ndb/config/win-sources \
- $(top_srcdir)/storage/ndb/config/win-libraries
- cat $(top_srcdir)/storage/ndb/config/win-lib.am > $@
- @$(top_srcdir)/storage/ndb/config/win-name $@ $(noinst_LIBRARIES)
- @$(top_srcdir)/storage/ndb/config/win-includes $@ $(INCLUDES)
- @$(top_srcdir)/storage/ndb/config/win-sources $@ $(libgrep_a_SOURCES)
- @$(top_srcdir)/storage/ndb/config/win-libraries $@ LIB $(LDADD)
diff --git a/storage/ndb/src/kernel/blocks/grep/systab_test/Makefile b/storage/ndb/src/kernel/blocks/grep/systab_test/Makefile
deleted file mode 100644
index bd69e0f3799..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/systab_test/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include .defs.mk
-
-TYPE := kernel
-
-BIN_TARGET := grep_systab_test
-BIN_TARGET_ARCHIVES := portlib general
-
-CCFLAGS_LOC += -I..
-
-SOURCES = ../GrepSystemTable.cpp grep_systab_test.cpp
-
-include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp b/storage/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp
deleted file mode 100644
index e3a77af4e4e..00000000000
--- a/storage/ndb/src/kernel/blocks/grep/systab_test/grep_systab_test.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/**
- * Unit Test for GrepSystemTable
- */
-
-#include "../GrepSystemTable.hpp"
-#include <SimulatedBlock.hpp>
-
-#define EXEC(X) ( ndbout << endl, ndbout_c(#X), X )
-
-int
-main () {
- GrepSystemTable st;
-
- Uint32 f, l;
-
- ndbout_c("*************************************");
- ndbout_c("* GrepSystemTable Unit Test Program *");
- ndbout_c("*************************************");
-
- ndbout_c("--------------------------------------------------------");
- ndbout_c("Test 1: Clear");
- ndbout_c("--------------------------------------------------------");
-
- EXEC(st.set(GrepSystemTable::PS, 22, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
-
- EXEC(st.clear(GrepSystemTable::PS, 20, 24));
- st.print();
- st.require(GrepSystemTable::PS, 25, 26);
-
- EXEC(st.clear(GrepSystemTable::PS, 0, 100));
- st.print();
- st.require(GrepSystemTable::PS, 1, 0);
-
- EXEC(st.set(GrepSystemTable::PS, 22, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
-
- EXEC(st.clear(GrepSystemTable::PS, 24, 28));
- st.print();
- st.require(GrepSystemTable::PS, 22, 23);
-
- EXEC(st.clear(GrepSystemTable::PS, 0, 100));
- st.print();
- st.require(GrepSystemTable::PS, 1, 0);
-
- EXEC(st.set(GrepSystemTable::PS, 22, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
-
- EXEC(st.clear(GrepSystemTable::PS, 24, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 23);
-
- EXEC(st.clear(GrepSystemTable::PS, 0, 100));
- st.print();
- st.require(GrepSystemTable::PS, 1, 0);
-
- EXEC(st.set(GrepSystemTable::PS, 22, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
-
- EXEC(st.clear(GrepSystemTable::PS, 22, 24));
- st.print();
- st.require(GrepSystemTable::PS, 25, 26);
-
- ndbout_c("--------------------------------------------------------");
- ndbout_c("Test 2: PS --> SSreq");
- ndbout_c("--------------------------------------------------------");
-
- EXEC(st.set(GrepSystemTable::PS, 22, 26));
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
- st.require(GrepSystemTable::SSReq, 1, 0);
-
- if (!EXEC(st.copy(GrepSystemTable::PS, GrepSystemTable::SSReq, 3, &f, &l)))
- ndbout_c("%s:%d: Illegal copy!", __FILE__, __FILE__);
- ndbout_c("f=%d, l=%d", f, l);
- st.print();
- st.require(GrepSystemTable::PS, 22, 26);
- st.require(GrepSystemTable::SSReq, 22, 24);
-
- EXEC(st.clear(GrepSystemTable::PS, 22, 22));
- st.print();
- st.require(GrepSystemTable::PS, 23, 26);
- st.require(GrepSystemTable::SSReq, 22, 24);
-
- if (!EXEC(st.copy(GrepSystemTable::PS, GrepSystemTable::SSReq, 2, &f, &l)))
- ndbout_c("%s:%d: Illegal copy!", __FILE__, __LINE__);
- ndbout_c("f=%d, l=%d", f, l);
- st.print();
- st.require(GrepSystemTable::PS, 23, 26);
- st.require(GrepSystemTable::SSReq, 22, 26);
-
- st.set(GrepSystemTable::SS, 7, 9);
- st.set(GrepSystemTable::InsReq, 7, 9);
- if (EXEC(st.movable(GrepSystemTable::SS, GrepSystemTable::InsReq)))
- ndbout_c("%s:%d: Illegal move!", __FILE__, __LINE__);
- st.print();
- st.require(GrepSystemTable::SS, 7, 9);
- st.require(GrepSystemTable::InsReq, 7, 9);
-
- EXEC(st.intervalMinus(7, 9, 7, 7, &f, &l));
- ndbout_c("f=%d, l=%d", f, l);
-
- st.clear(GrepSystemTable::InsReq, 8, 9);
- st.require(GrepSystemTable::SS, 7, 9);
- st.require(GrepSystemTable::InsReq, 7, 7);
- if (EXEC(st.movable(GrepSystemTable::SS, GrepSystemTable::InsReq)) != 2)
- ndbout_c("%s:%d: Illegal move!", __FILE__, __LINE__);
- st.print();
-
- EXEC(st.copy(GrepSystemTable::SS, GrepSystemTable::InsReq, &f));
- st.print();
- st.require(GrepSystemTable::SS, 7, 9);
- st.require(GrepSystemTable::InsReq, 7, 8);
-
- ndbout_c("--------------------------------------------------------");
- ndbout_c("Test completed");
- ndbout_c("--------------------------------------------------------");
-}
diff --git a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
index 524a40697bf..c837321a52d 100644
--- a/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
+++ b/storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
@@ -76,7 +76,6 @@ static BlockInfo ALL_BLOCKS[] = {
{ BACKUP_REF, 1 , 10000, 10999 },
{ DBUTIL_REF, 1 , 11000, 11999 },
{ SUMA_REF, 1 , 13000, 13999 },
- { GREP_REF, 1 , 0, 0 },
{ DBTUX_REF, 1 , 12000, 12999 }
};
@@ -1453,9 +1452,6 @@ void Ndbcntr::execNODE_FAILREP(Signal* signal)
sendSignal(SUMA_REF, GSN_NODE_FAILREP, signal,
NodeFailRep::SignalLength, JBB);
- sendSignal(GREP_REF, GSN_NODE_FAILREP, signal,
- NodeFailRep::SignalLength, JBB);
-
Uint32 nodeId = 0;
while(!allFailed.isclear()){
nodeId = allFailed.find(nodeId + 1);
@@ -2377,7 +2373,6 @@ void Ndbcntr::execREAD_CONFIG_CONF(Signal* signal){
void Ndbcntr::execSTART_ORD(Signal* signal){
jamEntry();
- ndbrequire(NO_OF_BLOCKS == ALL_BLOCKS_SZ);
c_missra.execSTART_ORD(signal);
}
@@ -2452,7 +2447,7 @@ void Ndbcntr::Missra::sendNextREAD_CONFIG_REQ(Signal* signal){
* Finished...
*/
currentStartPhase = 0;
- for(Uint32 i = 0; i<NO_OF_BLOCKS; i++){
+ for(Uint32 i = 0; i<ALL_BLOCKS_SZ; i++){
if(ALL_BLOCKS[i].NextSP < currentStartPhase)
currentStartPhase = ALL_BLOCKS[i].NextSP;
}
diff --git a/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
index 2f4fcd21460..f84fae02fc4 100644
--- a/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
+++ b/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
@@ -219,6 +219,7 @@ private:
void execAPI_VERSION_REQ(Signal* signal);
+ void execAPI_BROADCAST_REP(Signal* signal);
// Arbitration signals
void execARBIT_CFG(Signal* signal);
diff --git a/storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp b/storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
index ecaeadff47a..4061455092d 100644
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
@@ -83,7 +83,8 @@ Qmgr::Qmgr(const class Configuration & conf)
addRecSignal(GSN_API_FAILCONF, &Qmgr::execAPI_FAILCONF);
addRecSignal(GSN_READ_NODESREQ, &Qmgr::execREAD_NODESREQ);
addRecSignal(GSN_SET_VAR_REQ, &Qmgr::execSET_VAR_REQ);
-
+ addRecSignal(GSN_API_BROADCAST_REP, &Qmgr::execAPI_BROADCAST_REP);
+
// Arbitration signals
addRecSignal(GSN_ARBIT_PREPREQ, &Qmgr::execARBIT_PREPREQ);
addRecSignal(GSN_ARBIT_PREPCONF, &Qmgr::execARBIT_PREPCONF);
diff --git a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index d062f5afb7e..7052e0da98a 100644
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -34,6 +34,7 @@
#include <signaldata/BlockCommitOrd.hpp>
#include <signaldata/FailRep.hpp>
#include <signaldata/DisconnectRep.hpp>
+#include <signaldata/ApiBroadcast.hpp>
#include <ndb_version.h>
@@ -1703,16 +1704,6 @@ void Qmgr::sendApiFailReq(Signal* signal, Uint16 failedNodeNo)
sendSignal(DBDICT_REF, GSN_API_FAILREQ, signal, 2, JBA);
sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBA);
- /**
- * GREP also need the information that an API node
- * (actually a REP node) has failed.
- *
- * GREP does however NOT send a CONF on this signal, i.e.
- * the API_FAILREQ signal to GREP is like a REP signal
- * (i.e. without any confirmation).
- */
- sendSignal(GREP_REF, GSN_API_FAILREQ, signal, 2, JBA);
-
/**-------------------------------------------------------------------------
* THE OTHER NODE WAS AN API NODE. THE COMMUNICATION LINK IS ALREADY
* BROKEN AND THUS NO ACTION IS NEEDED TO BREAK THE CONNECTION.
@@ -3926,3 +3917,30 @@ void Qmgr::execSET_VAR_REQ(Signal* signal)
}// switch
#endif
}//execSET_VAR_REQ()
+
+void
+Qmgr::execAPI_BROADCAST_REP(Signal* signal)
+{
+ jamEntry();
+ ApiBroadcastRep api= *(const ApiBroadcastRep*)signal->getDataPtr();
+
+ Uint32 len = signal->getLength() - ApiBroadcastRep::SignalLength;
+ memmove(signal->theData, signal->theData+ApiBroadcastRep::SignalLength,
+ 4*len);
+
+ NodeBitmask mask;
+ NodeRecPtr nodePtr;
+ for (nodePtr.i = 1; nodePtr.i < MAX_NODES; nodePtr.i++)
+ {
+ jam();
+ ptrAss(nodePtr, nodeRec);
+ if (nodePtr.p->phase == ZAPI_ACTIVE &&
+ getNodeInfo(nodePtr.i).m_version >= api.minVersion)
+ {
+ mask.set(nodePtr.i);
+ }
+ }
+
+ NodeReceiverGroup rg(API_CLUSTERMGR, mask);
+ sendSignal(rg, api.gsn, signal, len, JBB); // forward sections
+}
diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp
index ed54505b729..c4225ad2a4c 100644
--- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp
+++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp
@@ -2185,7 +2185,8 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
case SubCreateReq::DatabaseSnapshot:
case SubCreateReq::SelectiveTableSnapshot:
jam();
- subbPtr.p->m_subscriberRef = GREP_REF;
+ ndbrequire(false);
+ //subbPtr.p->m_subscriberRef = GREP_REF;
subbPtr.p->m_subscriberData = subPtr.p->m_subscriberData;
break;
case SubCreateReq::SingleTableScan:
@@ -3018,16 +3019,6 @@ SumaParticipant::execSUB_GCP_COMPLETE_REP(Signal* signal){
c_lastCompleteGCI = gci;
/**
- * always send SUB_GCP_COMPLETE_REP to Grep (so
- * Lars can do funky stuff calculating intervals,
- * even before the subscription is started
- */
- rep->senderRef = reference();
- rep->senderData = 0; //ignored in grep
- EXECUTE_DIRECT(refToBlock(GREP_REF), GSN_SUB_GCP_COMPLETE_REP, signal,
- SubGcpCompleteRep::SignalLength);
-
- /**
* Signal to subscriber(s)
*/
@@ -3051,13 +3042,6 @@ SumaParticipant::execSUB_GCP_COMPLETE_REP(Signal* signal){
ndbout_c("GSN_SUB_GCP_COMPLETE_REP to %s:",
getBlockName(refToBlock(ref)));
#else
- /**
- * Ignore sending to GREP (since we sent earlier)
- */
- if (ref == GREP_REF) {
- jam();
- continue;
- }
CRASH_INSERTION(13018);
diff --git a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp
index 35c0781a24d..ef9f2c3c716 100644
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp
@@ -1802,3 +1802,118 @@ SimulatedBlock::init_globals_list(void ** tmp, size_t cnt){
}
#endif
+
+#include "KeyDescriptor.hpp"
+
+Uint32
+SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src,
+ Uint32 *dst, Uint32 dstSize,
+ Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const
+{
+ const KeyDescriptor * desc = g_key_descriptor_pool.getPtr(tab);
+ const Uint32 noOfKeyAttr = desc->noOfKeyAttr;
+
+ Uint32 i = 0;
+ Uint32 srcPos = 0;
+ Uint32 dstPos = 0;
+ while (i < noOfKeyAttr)
+ {
+ const KeyDescriptor::KeyAttr& keyAttr = desc->keyAttr[i];
+
+ Uint32 srcBytes =
+ AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
+ Uint32 srcWords = (srcBytes + 3) / 4;
+ Uint32 dstWords = ~0;
+ uchar* dstPtr = (uchar*)&dst[dstPos];
+ const uchar* srcPtr = (const uchar*)&src[srcPos];
+ CHARSET_INFO* cs = keyAttr.charsetInfo;
+
+ if (cs == NULL)
+ {
+ jam();
+ memcpy(dstPtr, srcPtr, srcWords << 2);
+ dstWords = srcWords;
+ }
+ else
+ {
+ jam();
+ Uint32 typeId =
+ AttributeDescriptor::getType(keyAttr.attributeDescriptor);
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ ndbrequire(ok);
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ /*
+ * Varchar is really Char. End spaces do not matter. To get
+ * same hash we blank-pad to maximum length via strnxfrm.
+ * TODO use MySQL charset-aware hash function instead
+ */
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0)
+ {
+ dstPtr[n++] = 0;
+ }
+ dstWords = (n >> 2);
+ }
+ dstPos += dstWords;
+ srcPos += srcWords;
+ keyPartLen[i++] = dstWords;
+ }
+
+ return dstPos;
+}
+
+Uint32
+SimulatedBlock::create_distr_key(Uint32 tableId,
+ Uint32 *data,
+ const Uint32
+ keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const
+{
+ const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tableId);
+ const Uint32 noOfKeyAttr = desc->noOfKeyAttr;
+ Uint32 noOfDistrKeys = desc->noOfDistrKeys;
+
+ Uint32 *src = data;
+ Uint32 *dst = data;
+ Uint32 i = 0;
+ Uint32 dstPos = 0;
+
+ if(keyPartLen)
+ {
+ while (i < noOfKeyAttr && noOfDistrKeys)
+ {
+ Uint32 attr = desc->keyAttr[i].attributeDescriptor;
+ Uint32 len = keyPartLen[i];
+ if(AttributeDescriptor::getDKey(attr))
+ {
+ noOfDistrKeys--;
+ memmove(dst+dstPos, src, len << 2);
+ dstPos += len;
+ }
+ src += len;
+ i++;
+ }
+ }
+ else
+ {
+ while (i < noOfKeyAttr && noOfDistrKeys)
+ {
+ Uint32 attr = desc->keyAttr[i].attributeDescriptor;
+ Uint32 len = AttributeDescriptor::getSizeInWords(attr);
+ if(AttributeDescriptor::getDKey(attr))
+ {
+ noOfDistrKeys--;
+ memmove(dst+dstPos, src, len << 2);
+ dstPos += len;
+ }
+ src += len;
+ i++;
+ }
+ }
+ return dstPos;
+}
diff --git a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp
index 787d14ca5cb..50c85a0b274 100644
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp
@@ -20,11 +20,13 @@
#include <NdbTick.h>
#include <kernel_types.h>
#include <ndb_version.h>
+#include <ndb_limits.h>
#include "VMSignal.hpp"
#include <RefConvert.hpp>
#include <BlockNumbers.h>
#include <GlobalSignalNumbers.h>
+
#include "pc.hpp"
#include <NodeInfo.hpp>
#include <NodeState.hpp>
@@ -385,6 +387,24 @@ protected:
*/
const NodeInfo & getNodeInfo(NodeId nodeId) const;
NodeInfo & setNodeInfo(NodeId);
+
+ /**********************
+ * Xfrm stuff
+ */
+
+ /**
+ * @return length
+ */
+ Uint32 xfrm_key(Uint32 tab, const Uint32* src,
+ Uint32 *dst, Uint32 dstLen,
+ Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const;
+
+ /**
+ *
+ */
+ Uint32 create_distr_key(Uint32 tableId,
+ Uint32 *data,
+ const Uint32 keyPaLen[MAX_ATTRIBUTES_IN_INDEX])const;
private:
NewVARIABLE* NewVarRef; /* New Base Address Table for block */
diff --git a/storage/ndb/src/mgmapi/mgmapi.cpp b/storage/ndb/src/mgmapi/mgmapi.cpp
index 1cfc46ae078..c10eb073855 100644
--- a/storage/ndb/src/mgmapi/mgmapi.cpp
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp
@@ -335,15 +335,21 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
const Properties* p = parser.parse(ctx, session);
if (p == NULL){
- /**
- * Print some info about why the parser returns NULL
- */
- fprintf(handle->errstream,
- "Error in mgm protocol parser. cmd: >%s< status: %d curr: %d\n",
- cmd, (Uint32)ctx.m_status, ctx.m_currentToken);
- DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s",
- ctx.m_status, ctx.m_currentToken));
- }
+ if(!ndb_mgm_is_connected(handle)) {
+ return NULL;
+ }
+ else
+ {
+ /**
+ * Print some info about why the parser returns NULL
+ */
+ fprintf(handle->errstream,
+ "Error in mgm protocol parser. cmd: >%s< status: %d curr: %d\n",
+ cmd, (Uint32)ctx.m_status, ctx.m_currentToken);
+ DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s",
+ ctx.m_status, ctx.m_currentToken));
+ }
+ }
#ifdef MGMAPI_LOG
else {
/**
@@ -363,6 +369,15 @@ int ndb_mgm_is_connected(NdbMgmHandle handle)
{
if(!handle)
return 0;
+
+ if(handle->connected)
+ {
+ if(Ndb_check_socket_hup(handle->socket))
+ {
+ handle->connected= 0;
+ NDB_CLOSE_SOCKET(handle->socket);
+ }
+ }
return handle->connected;
}
diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp
index 51356cb75b1..14d4f768c86 100644
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -2581,44 +2581,7 @@ MgmtSrvr::backupCallback(BackupEvent & event)
int
MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted)
{
- bool next;
- NodeId nodeId = 0;
-
- while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
- theFacade->get_node_alive(nodeId) == false);
-
- if(!next){
- return NO_CONTACT_WITH_DB_NODES;
- }
-
- NdbApiSignal* signal = getSignal();
- if (signal == NULL) {
- return COULD_NOT_ALLOCATE_MEMORY;
- }
-
- GrepReq* req = CAST_PTR(GrepReq, signal->getDataPtrSend());
- signal->set(TestOrd::TraceAPI, GREP, GSN_GREP_REQ, GrepReq::SignalLength);
- req->senderRef = _ownReference;
- req->request = request;
-
- int result;
- if (waitCompleted)
- result = sendRecSignal(nodeId, NO_WAIT, signal, true);
- else
- result = sendRecSignal(nodeId, NO_WAIT, signal, true);
- if (result == -1) {
- return SEND_OR_RECEIVE_FAILED;
- }
-
- /**
- * @todo
- * Maybe add that we should receive a confirmation that the
- * request was received ok.
- * Then we should give the user the correct repReqId.
- */
-
- *repReqId = 4711;
-
+ abort();
return 0;
}
diff --git a/storage/ndb/src/ndbapi/DictCache.cpp b/storage/ndb/src/ndbapi/DictCache.cpp
index 3d14df908a0..57d9b361522 100644
--- a/storage/ndb/src/ndbapi/DictCache.cpp
+++ b/storage/ndb/src/ndbapi/DictCache.cpp
@@ -21,6 +21,9 @@
#include <NdbCondition.h>
#include <NdbSleep.h>
+static NdbTableImpl f_invalid_table;
+static NdbTableImpl f_altered_table;
+
Ndb_local_table_info *
Ndb_local_table_info::create(NdbTableImpl *table_impl, Uint32 sz)
{
@@ -203,21 +206,41 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab)
TableVersion & ver = vers->back();
if(ver.m_status != RETREIVING ||
- ver.m_impl != 0 ||
+ !(ver.m_impl == 0 ||
+ ver.m_impl == &f_invalid_table || ver.m_impl == &f_altered_table) ||
ver.m_version != 0 ||
ver.m_refCount == 0){
abort();
}
- if(tab == 0){
+ if(tab == 0)
+ {
DBUG_PRINT("info", ("No table found in db"));
vers->erase(sz - 1);
- } else {
+ }
+ else if (ver.m_impl == 0) {
ver.m_impl = tab;
ver.m_version = tab->m_version;
ver.m_status = OK;
+ }
+ else if (ver.m_impl == &f_invalid_table)
+ {
+ ver.m_impl = tab;
+ ver.m_version = tab->m_version;
+ ver.m_status = DROPPED;
+ ver.m_impl->m_status = NdbDictionary::Object::Invalid;
+ }
+ else if(ver.m_impl == &f_altered_table)
+ {
+ ver.m_impl = tab;
+ ver.m_version = tab->m_version;
+ ver.m_status = DROPPED;
+ ver.m_impl->m_status = NdbDictionary::Object::Altered;
+ }
+ else
+ {
+ abort();
}
-
NdbCondition_Broadcast(m_waitForTableCondition);
DBUG_RETURN(tab);
}
@@ -325,4 +348,45 @@ GlobalDictCache::release(NdbTableImpl * tab)
abort();
}
+void
+GlobalDictCache::alter_table_rep(const char * name,
+ Uint32 tableId,
+ Uint32 tableVersion,
+ bool altered)
+{
+ const Uint32 len = strlen(name);
+ Vector<TableVersion> * vers =
+ m_tableHash.getData(name, len);
+
+ if(vers == 0)
+ {
+ return;
+ }
+
+ const Uint32 sz = vers->size();
+ if(sz == 0)
+ {
+ return;
+ }
+
+ for(Uint32 i = 0; i < sz; i++)
+ {
+ TableVersion & ver = (* vers)[i];
+ if(ver.m_version == tableVersion && ver.m_impl &&
+ ver.m_impl->m_tableId == tableId)
+ {
+ ver.m_status = DROPPED;
+ ver.m_impl->m_status = altered ?
+ NdbDictionary::Object::Altered : NdbDictionary::Object::Invalid;
+ return;
+ }
+
+ if(i == sz - 1 && ver.m_status == RETREIVING)
+ {
+ ver.m_impl = altered ? &f_altered_table : &f_invalid_table;
+ return;
+ }
+ }
+}
+
template class Vector<GlobalDictCache::TableVersion>;
diff --git a/storage/ndb/src/ndbapi/DictCache.hpp b/storage/ndb/src/ndbapi/DictCache.hpp
index d9bf810a685..2df6a139542 100644
--- a/storage/ndb/src/ndbapi/DictCache.hpp
+++ b/storage/ndb/src/ndbapi/DictCache.hpp
@@ -68,6 +68,9 @@ public:
NdbTableImpl* put(const char * name, NdbTableImpl *);
void drop(NdbTableImpl *);
void release(NdbTableImpl *);
+
+ void alter_table_rep(const char * name,
+ Uint32 tableId, Uint32 tableVersion, bool altered);
public:
enum Status {
OK = 0,
diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index 582f4baaef4..529ba09207b 100644
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -1564,25 +1564,22 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl)
const char * originalInternalName = internalName.c_str();
DBUG_ENTER("NdbDictionaryImpl::alterTable");
- if(!get_local_table_info(internalName, false)){
- m_error.code= 709;
+ Ndb_local_table_info * local = 0;
+ if((local= get_local_table_info(originalInternalName, false)) == 0)
+ {
+ m_error.code = 709;
DBUG_RETURN(-1);
}
+
// Alter the table
int ret = m_receiver.alterTable(m_ndb, impl);
if(ret == 0){
// Remove cached information and let it be refreshed at next access
- if (m_localHash.get(originalInternalName) != NULL) {
- m_localHash.drop(originalInternalName);
- m_globalHash->lock();
- NdbTableImpl * cachedImpl = m_globalHash->get(originalInternalName);
- // If in local cache it must be in global
- if (!cachedImpl)
- abort();
- cachedImpl->m_status = NdbDictionary::Object::Invalid;
- m_globalHash->drop(cachedImpl);
- m_globalHash->unlock();
- }
+ m_globalHash->lock();
+ local->m_table_impl->m_status = NdbDictionary::Object::Invalid;
+ m_globalHash->drop(local->m_table_impl);
+ m_globalHash->unlock();
+ m_localHash.drop(originalInternalName);
}
DBUG_RETURN(ret);
}
diff --git a/storage/ndb/src/ndbapi/TransporterFacade.cpp b/storage/ndb/src/ndbapi/TransporterFacade.cpp
index 20d2b11c0ac..638eae15c24 100644
--- a/storage/ndb/src/ndbapi/TransporterFacade.cpp
+++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp
@@ -35,6 +35,7 @@
#include <ndb_version.h>
#include <SignalLoggerManager.hpp>
#include <kernel/ndb_limits.h>
+#include <signaldata/AlterTable.hpp>
//#define REPORT_TRANSPORTER
//#define API_TRACE;
@@ -309,6 +310,17 @@ execute(void * callbackObj, SignalHeader * const header,
theFacade->theArbitMgr->doStop(theData);
break;
+ case GSN_ALTER_TABLE_REP:
+ {
+ const AlterTableRep* rep = (const AlterTableRep*)theData;
+ theFacade->m_globalDictCache.lock();
+ theFacade->m_globalDictCache.
+ alter_table_rep((const char*)ptr[0].p,
+ rep->tableId,
+ rep->tableVersion,
+ rep->changeType == AlterTableRep::CT_ALTERED);
+ theFacade->m_globalDictCache.unlock();
+ }
default:
break;
diff --git a/storage/ndb/test/ndbapi/testGrep.cpp b/storage/ndb/test/ndbapi/testGrep.cpp
deleted file mode 100644
index 713aefbeafa..00000000000
--- a/storage/ndb/test/ndbapi/testGrep.cpp
+++ /dev/null
@@ -1,540 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include <NDBT.hpp>
-#include <NDBT_Test.hpp>
-#include <HugoTransactions.hpp>
-#include <UtilTransactions.hpp>
-#include <NdbGrep.hpp>
-
-
-#define CHECK(b) if (!(b)) { \
- g_err << "ERR: "<< step->getName() \
- << " failed on line " << __LINE__ << endl; \
- result = NDBT_FAILED; \
- continue; }
-
-
-int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
-
- int records = ctx->getNumRecords();
- HugoTransactions hugoTrans(*ctx->getTab());
- if (hugoTrans.loadTable(GETNDB(step), records) != 0){
- return NDBT_FAILED;
- }
- return NDBT_OK;
-}
-
-int runPkUpdate(NDBT_Context* ctx, NDBT_Step* step){
- int loops = ctx->getNumLoops();
- int records = ctx->getNumRecords();
- int batchSize = ctx->getProperty("BatchSize", 1);
- int i = 0;
- HugoTransactions hugoTrans(*ctx->getTab());
- while (i<loops) {
- g_info << "|- " << i << ": ";
- if (hugoTrans.pkUpdateRecords(GETNDB(step), records, batchSize) != 0){
- g_info << endl;
- return NDBT_FAILED;
- }
- i++;
- }
- g_info << endl;
- return NDBT_OK;
-}
-
-int runRestartInitial(NDBT_Context* ctx, NDBT_Step* step){
- NdbRestarter restarter;
-
- Ndb* pNdb = GETNDB(step);
-
- const NdbDictionary::Table *tab = ctx->getTab();
- pNdb->getDictionary()->dropTable(tab->getName());
-
- if (restarter.restartAll(true) != 0)
- return NDBT_FAILED;
-
- return NDBT_OK;
-}
-
-int runRestarter(NDBT_Context* ctx, NDBT_Step* step){
- int result = NDBT_OK;
- int loops = ctx->getNumLoops();
- NdbRestarter restarter;
- int i = 0;
- int lastId = 0;
-
- if (restarter.getNumDbNodes() < 2){
- ctx->stopTest();
- return NDBT_OK;
- }
-
- if(restarter.waitClusterStarted(60) != 0){
- g_err << "Cluster failed to start" << endl;
- return NDBT_FAILED;
- }
-
- loops *= restarter.getNumDbNodes();
- while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
-
- int id = lastId % restarter.getNumDbNodes();
- int nodeId = restarter.getDbNodeId(id);
- ndbout << "Restart node " << nodeId << endl;
- if(restarter.restartOneDbNode(nodeId) != 0){
- g_err << "Failed to restartNextDbNode" << endl;
- result = NDBT_FAILED;
- break;
- }
-
- if(restarter.waitClusterStarted(60) != 0){
- g_err << "Cluster failed to start" << endl;
- result = NDBT_FAILED;
- break;
- }
-
- NdbSleep_SecSleep(1);
-
- lastId++;
- i++;
- }
-
- ctx->stopTest();
-
- return result;
-}
-
-int runCheckAllNodesStarted(NDBT_Context* ctx, NDBT_Step* step){
- NdbRestarter restarter;
-
- if(restarter.waitClusterStarted(1) != 0){
- g_err << "All nodes was not started " << endl;
- return NDBT_FAILED;
- }
-
- return NDBT_OK;
-}
-
-
-bool testMaster = true;
-bool testSlave = false;
-
-int setMaster(NDBT_Context* ctx, NDBT_Step* step){
- testMaster = true;
- testSlave = false;
- return NDBT_OK;
-}
-int setMasterAsSlave(NDBT_Context* ctx, NDBT_Step* step){
- testMaster = true;
- testSlave = true;
- return NDBT_OK;
-}
-int setSlave(NDBT_Context* ctx, NDBT_Step* step){
- testMaster = false;
- testSlave = true;
- return NDBT_OK;
-}
-
-int runAbort(NDBT_Context* ctx, NDBT_Step* step){
-
-
- NdbGrep grep(GETNDB(step)->getNodeId()+1);
- NdbRestarter restarter;
-
- if (restarter.getNumDbNodes() < 2){
- ctx->stopTest();
- return NDBT_OK;
- }
-
- if(restarter.waitClusterStarted(60) != 0){
- g_err << "Cluster failed to start" << endl;
- return NDBT_FAILED;
- }
-
- if (testMaster) {
- if (testSlave) {
- if (grep.NFMasterAsSlave(restarter) == -1){
- return NDBT_FAILED;
- }
- } else {
- if (grep.NFMaster(restarter) == -1){
- return NDBT_FAILED;
- }
- }
- } else {
- if (grep.NFSlave(restarter) == -1){
- return NDBT_FAILED;
- }
- }
-
- return NDBT_OK;
-}
-
-int runFail(NDBT_Context* ctx, NDBT_Step* step){
- NdbGrep grep(GETNDB(step)->getNodeId()+1);
-
- NdbRestarter restarter;
-
- if (restarter.getNumDbNodes() < 2){
- ctx->stopTest();
- return NDBT_OK;
- }
-
- if(restarter.waitClusterStarted(60) != 0){
- g_err << "Cluster failed to start" << endl;
- return NDBT_FAILED;
- }
-
- if (testMaster) {
- if (testSlave) {
- if (grep.FailMasterAsSlave(restarter) == -1){
- return NDBT_FAILED;
- }
- } else {
- if (grep.FailMaster(restarter) == -1){
- return NDBT_FAILED;
- }
- }
- } else {
- if (grep.FailSlave(restarter) == -1){
- return NDBT_FAILED;
- }
- }
-
- return NDBT_OK;
-}
-
-int runGrepBasic(NDBT_Context* ctx, NDBT_Step* step){
- NdbGrep grep(GETNDB(step)->getNodeId()+1);
- unsigned grepId = 0;
-
- if (grep.start() == -1){
- return NDBT_FAILED;
- }
- ndbout << "Started grep " << grepId << endl;
- ctx->setProperty("GrepId", grepId);
-
- return NDBT_OK;
-}
-
-
-
-
-int runVerifyBasic(NDBT_Context* ctx, NDBT_Step* step){
- NdbGrep grep(GETNDB(step)->getNodeId()+1, ctx->getRemoteMgm());
- ndbout_c("no of nodes %d" ,grep.getNumDbNodes());
- int result;
- if ((result = grep.verify(ctx)) == -1){
- return NDBT_FAILED;
- }
- return result;
-}
-
-
-
-int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
- int records = ctx->getNumRecords();
-
- UtilTransactions utilTrans(*ctx->getTab());
- if (utilTrans.clearTable2(GETNDB(step), records) != 0){
- return NDBT_FAILED;
- }
- return NDBT_OK;
-}
-
-#include "bank/Bank.hpp"
-
-int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- int overWriteExisting = true;
- if (bank.createAndLoadBank(overWriteExisting) != NDBT_OK)
- return NDBT_FAILED;
- return NDBT_OK;
-}
-
-int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- int wait = 30; // Max seconds between each "day"
- int yield = 1; // Loops before bank returns
-
- while (ctx->isTestStopped() == false) {
- bank.performIncreaseTime(wait, yield);
- }
- return NDBT_OK;
-}
-
-int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- int wait = 10; // Max ms between each transaction
- int yield = 100; // Loops before bank returns
-
- while (ctx->isTestStopped() == false) {
- bank.performTransactions(wait, yield);
- }
- return NDBT_OK;
-}
-
-int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- int yield = 20; // Loops before bank returns
- int result = NDBT_OK;
-
- while (ctx->isTestStopped() == false) {
- if (bank.performMakeGLs(yield) != NDBT_OK){
- ndbout << "bank.performMakeGLs FAILED" << endl;
- result = NDBT_FAILED;
- }
- }
- return NDBT_OK;
-}
-
-int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- int wait = 2000; // Max ms between each sum of accounts
- int yield = 1; // Loops before bank returns
- int result = NDBT_OK;
-
- while (ctx->isTestStopped() == false) {
- if (bank.performSumAccounts(wait, yield) != NDBT_OK){
- ndbout << "bank.performSumAccounts FAILED" << endl;
- result = NDBT_FAILED;
- }
- }
- return result ;
-}
-
-int runDropBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
- if (bank.dropBank() != NDBT_OK)
- return NDBT_FAILED;
- return NDBT_OK;
-}
-
-int runGrepBank(NDBT_Context* ctx, NDBT_Step* step){
- int loops = ctx->getNumLoops();
- int l = 0;
- int maxSleep = 30; // Max seconds between each grep
- Ndb* pNdb = GETNDB(step);
- NdbGrep grep(GETNDB(step)->getNodeId()+1);
- unsigned minGrepId = ~0;
- unsigned maxGrepId = 0;
- unsigned grepId = 0;
- int result = NDBT_OK;
-
- while (l < loops && result != NDBT_FAILED){
-
- if (pNdb->waitUntilReady() != 0){
- result = NDBT_FAILED;
- continue;
- }
-
- // Sleep for a while
- NdbSleep_SecSleep(maxSleep);
-
- // Perform grep
- if (grep.start() != 0){
- ndbout << "grep.start failed" << endl;
- result = NDBT_FAILED;
- continue;
- }
- ndbout << "Started grep " << grepId << endl;
-
- // Remember min and max grepid
- if (grepId < minGrepId)
- minGrepId = grepId;
-
- if (grepId > maxGrepId)
- maxGrepId = grepId;
-
- ndbout << " maxGrepId = " << maxGrepId
- << ", minGrepId = " << minGrepId << endl;
- ctx->setProperty("MinGrepId", minGrepId);
- ctx->setProperty("MaxGrepId", maxGrepId);
-
- l++;
- }
-
- ctx->stopTest();
-
- return result;
-}
-/*
-int runRestoreBankAndVerify(NDBT_Context* ctx, NDBT_Step* step){
- NdbRestarter restarter;
- NdbGrep grep(GETNDB(step)->getNodeId()+1);
- unsigned minGrepId = ctx->getProperty("MinGrepId");
- unsigned maxGrepId = ctx->getProperty("MaxGrepId");
- unsigned grepId = minGrepId;
- int result = NDBT_OK;
- int errSumAccounts = 0;
- int errValidateGL = 0;
-
- ndbout << " maxGrepId = " << maxGrepId << endl;
- ndbout << " minGrepId = " << minGrepId << endl;
-
- while (grepId <= maxGrepId){
-
- // TEMPORARY FIX
- // To erase all tables from cache(s)
- // To be removed, maybe replaced by ndb.invalidate();
- {
- Bank bank;
-
- if (bank.dropBank() != NDBT_OK){
- result = NDBT_FAILED;
- break;
- }
- }
- // END TEMPORARY FIX
-
- ndbout << "Performing initial restart" << endl;
- if (restarter.restartAll(true) != 0)
- return NDBT_FAILED;
-
- if (restarter.waitClusterStarted() != 0)
- return NDBT_FAILED;
-
- ndbout << "Restoring grep " << grepId << endl;
- if (grep.restore(grepId) == -1){
- return NDBT_FAILED;
- }
- ndbout << "Grep " << grepId << " restored" << endl;
-
- // Let bank verify
- Bank bank;
-
- int wait = 0;
- int yield = 1;
- if (bank.performSumAccounts(wait, yield) != 0){
- ndbout << "bank.performSumAccounts FAILED" << endl;
- ndbout << " grepId = " << grepId << endl << endl;
- result = NDBT_FAILED;
- errSumAccounts++;
- }
-
- if (bank.performValidateAllGLs() != 0){
- ndbout << "bank.performValidateAllGLs FAILED" << endl;
- ndbout << " grepId = " << grepId << endl << endl;
- result = NDBT_FAILED;
- errValidateGL++;
- }
-
- grepId++;
- }
-
- if (result != NDBT_OK){
- ndbout << "Verification of grep failed" << endl
- << " errValidateGL="<<errValidateGL<<endl
- << " errSumAccounts="<<errSumAccounts<<endl << endl;
- }
-
- return result;
-}
-*/
-
-NDBT_TESTSUITE(testGrep);
-TESTCASE("GrepBasic",
- "Test that Global Replication works on one table \n"
- "1. Load table\n"
- "2. Grep\n"
- "3. Restart -i\n"
- "4. Restore\n"
- "5. Verify count and content of table\n"){
- INITIALIZER(runLoadTable);
- VERIFIER(runVerifyBasic);
- FINALIZER(runClearTable);
-
-}
-
-TESTCASE("GrepNodeRestart",
- "Test that Global Replication works on one table \n"
- "1. Load table\n"
- "2. Grep\n"
- "3. Restart -i\n"
- "4. Restore\n"
- "5. Verify count and content of table\n"){
- INITIALIZER(runLoadTable);
- STEP(runPkUpdate);
- STEP(runRestarter);
- VERIFIER(runVerifyBasic);
- FINALIZER(runClearTable);
-}
-
-
-TESTCASE("GrepBank",
- "Test that grep and restore works during transaction load\n"
- " by backing up the bank"
- "1. Create bank\n"
- "2a. Start bank and let it run\n"
- "2b. Perform loop number of greps of the bank\n"
- " when greps are finished tell bank to close\n"
- "3. Restart ndb -i and reload each grep\n"
- " let bank verify that the grep is consistent\n"
- "4. Drop bank\n"){
- INITIALIZER(runCreateBank);
- STEP(runBankTimer);
- STEP(runBankTransactions);
- STEP(runBankGL);
- // TODO STEP(runBankSum);
- STEP(runGrepBank);
- // VERIFIER(runRestoreBankAndVerify);
- // FINALIZER(runDropBank);
-
-}
-
-TESTCASE("NFMaster",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setMaster);
- STEP(runAbort);
-
-}
-TESTCASE("NFMasterAsSlave",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setMasterAsSlave);
- STEP(runAbort);
-
-}
-TESTCASE("NFSlave",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setSlave);
- STEP(runAbort);
-
-}
-TESTCASE("FailMaster",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setMaster);
- STEP(runFail);
-
-}
-TESTCASE("FailMasterAsSlave",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setMasterAsSlave);
- STEP(runFail);
-
-}
-TESTCASE("FailSlave",
- "Test that grep behaves during node failiure\n"){
- INITIALIZER(setSlave);
- STEP(runFail);
-
-}
-NDBT_TESTSUITE_END(testGrep);
-
-int main(int argc, const char** argv){
- ndb_init();
- return testGrep.execute(argc, argv);
-}
-
-
diff --git a/strings/Makefile.am b/strings/Makefile.am
index ad652862222..c43cf0f290a 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -22,7 +22,7 @@ pkglib_LIBRARIES = libmystrings.a
# Exact one of ASSEMBLER_X
if ASSEMBLER_x86
ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c
+CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c longlong2str_asm.c
else
if ASSEMBLER_sparc32
# These file MUST all be on the same line!! Otherwise automake
@@ -45,7 +45,7 @@ EXTRA_DIST = ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc
ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
xml.c decimal.c strto.c strings-x86.s \
- longlong2str.c longlong2str-x86.s \
+ longlong2str.c longlong2str-x86.s longlong2str_asm.c \
my_strtoll10.c my_strtoll10-x86.s \
strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
strfill.c strcend.c is_prefix.c strstr.c strinstr.c \
diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c
index 9ccbb149523..5069a1dc082 100644
--- a/strings/ctype-big5.c
+++ b/strings/ctype-big5.c
@@ -6399,6 +6399,7 @@ CHARSET_INFO my_charset_big5_chinese_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_big5_handler,
&my_collation_big5_chinese_ci_handler
};
@@ -6430,6 +6431,7 @@ CHARSET_INFO my_charset_big5_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_big5_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 40ecbc33d61..0fcd9021c4b 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -539,6 +539,7 @@ CHARSET_INFO my_charset_bin =
1, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_binary_handler
};
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c
index f62cf2db599..b5f36c030bd 100644
--- a/strings/ctype-cp932.c
+++ b/strings/ctype-cp932.c
@@ -5522,6 +5522,7 @@ CHARSET_INFO my_charset_cp932_japanese_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 1, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -5552,6 +5553,7 @@ CHARSET_INFO my_charset_cp932_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 1, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c
index 1361b728b26..bdafc5c94b6 100644
--- a/strings/ctype-czech.c
+++ b/strings/ctype-czech.c
@@ -628,6 +628,7 @@ CHARSET_INFO my_charset_latin2_czech_ci =
1, /* mbmaxlen */
0, /* min_sort_char */
0, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_8bit_handler,
&my_collation_latin2_czech_ci_handler
};
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index e2167aa315e..b529bbb0308 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -8706,6 +8706,7 @@ CHARSET_INFO my_charset_euckr_korean_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -8737,6 +8738,7 @@ CHARSET_INFO my_charset_euckr_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c
index 2ab103d65ac..ccdca2ba595 100644
--- a/strings/ctype-eucjpms.c
+++ b/strings/ctype-eucjpms.c
@@ -8708,6 +8708,7 @@ CHARSET_INFO my_charset_eucjpms_japanese_ci=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -8739,6 +8740,7 @@ CHARSET_INFO my_charset_eucjpms_bin=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-extra.c b/strings/ctype-extra.c
index 2544245bc42..e9a9598abdf 100644
--- a/strings/ctype-extra.c
+++ b/strings/ctype-extra.c
@@ -43,6 +43,7 @@ CHARSET_INFO compiled_charsets[] = {
0, /* mbmaxlen */
0, /* min_sort_ord */
0, /* max_sort_ord */
+ 0, /* escape_with_backslash_is_dangerous */
NULL, /* cset handler */
NULL /* coll handler */
}
diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c
index 6b582081085..3d9a17205cd 100644
--- a/strings/ctype-gb2312.c
+++ b/strings/ctype-gb2312.c
@@ -5757,6 +5757,7 @@ CHARSET_INFO my_charset_gb2312_chinese_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -5787,6 +5788,7 @@ CHARSET_INFO my_charset_gb2312_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c
index 7caef07202d..5c220a285dd 100644
--- a/strings/ctype-gbk.c
+++ b/strings/ctype-gbk.c
@@ -10046,6 +10046,7 @@ CHARSET_INFO my_charset_gbk_chinese_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -10076,6 +10077,7 @@ CHARSET_INFO my_charset_gbk_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c
index 7d54dd47552..9075710610b 100644
--- a/strings/ctype-latin1.c
+++ b/strings/ctype-latin1.c
@@ -441,6 +441,7 @@ CHARSET_INFO my_charset_latin1=
1, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_8bit_simple_ci_handler
};
@@ -739,6 +740,7 @@ CHARSET_INFO my_charset_latin1_german2_ci=
1, /* mbmaxlen */
0, /* min_sort_char */
247, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_german2_ci_handler
};
@@ -770,6 +772,7 @@ CHARSET_INFO my_charset_latin1_bin=
1, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_8bit_bin_handler
};
diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c
index 1c12df08b32..c0a395b5792 100644
--- a/strings/ctype-sjis.c
+++ b/strings/ctype-sjis.c
@@ -4696,6 +4696,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -4726,6 +4727,7 @@ CHARSET_INFO my_charset_sjis_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c
index e445fa90bd3..2003eaa0789 100644
--- a/strings/ctype-tis620.c
+++ b/strings/ctype-tis620.c
@@ -993,6 +993,7 @@ CHARSET_INFO my_charset_tis620_thai_ci=
1, /* mbmaxlen */
0, /* min_sort_char */
0, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -1023,6 +1024,7 @@ CHARSET_INFO my_charset_tis620_bin=
1, /* mbmaxlen */
0, /* min_sort_char */
0, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_8bit_bin_handler
};
diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c
index 8bc48b3609d..dcf1c07113e 100644
--- a/strings/ctype-uca.c
+++ b/strings/ctype-uca.c
@@ -8059,6 +8059,7 @@ CHARSET_INFO my_charset_ucs2_general_uca=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8089,6 +8090,7 @@ CHARSET_INFO my_charset_ucs2_icelandic_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8119,6 +8121,7 @@ CHARSET_INFO my_charset_ucs2_latvian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8149,6 +8152,7 @@ CHARSET_INFO my_charset_ucs2_romanian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8179,6 +8183,7 @@ CHARSET_INFO my_charset_ucs2_slovenian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8209,6 +8214,7 @@ CHARSET_INFO my_charset_ucs2_polish_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8239,6 +8245,7 @@ CHARSET_INFO my_charset_ucs2_estonian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8269,6 +8276,7 @@ CHARSET_INFO my_charset_ucs2_spanish_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8299,6 +8307,7 @@ CHARSET_INFO my_charset_ucs2_swedish_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8329,6 +8338,7 @@ CHARSET_INFO my_charset_ucs2_turkish_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8359,6 +8369,7 @@ CHARSET_INFO my_charset_ucs2_czech_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8390,6 +8401,7 @@ CHARSET_INFO my_charset_ucs2_danish_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8420,6 +8432,7 @@ CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8450,6 +8463,7 @@ CHARSET_INFO my_charset_ucs2_slovak_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8480,6 +8494,7 @@ CHARSET_INFO my_charset_ucs2_spanish2_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8511,6 +8526,7 @@ CHARSET_INFO my_charset_ucs2_roman_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8542,6 +8558,7 @@ CHARSET_INFO my_charset_ucs2_persian_uca_ci=
2, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_uca_handler
};
@@ -8620,6 +8637,7 @@ CHARSET_INFO my_charset_utf8_general_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8651,6 +8669,7 @@ CHARSET_INFO my_charset_utf8_icelandic_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8681,6 +8700,7 @@ CHARSET_INFO my_charset_utf8_latvian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8711,6 +8731,7 @@ CHARSET_INFO my_charset_utf8_romanian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8741,6 +8762,7 @@ CHARSET_INFO my_charset_utf8_slovenian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8771,6 +8793,7 @@ CHARSET_INFO my_charset_utf8_polish_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8801,6 +8824,7 @@ CHARSET_INFO my_charset_utf8_estonian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8831,6 +8855,7 @@ CHARSET_INFO my_charset_utf8_spanish_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8861,6 +8886,7 @@ CHARSET_INFO my_charset_utf8_swedish_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8891,6 +8917,7 @@ CHARSET_INFO my_charset_utf8_turkish_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8921,6 +8948,7 @@ CHARSET_INFO my_charset_utf8_czech_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8952,6 +8980,7 @@ CHARSET_INFO my_charset_utf8_danish_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -8982,6 +9011,7 @@ CHARSET_INFO my_charset_utf8_lithuanian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -9012,6 +9042,7 @@ CHARSET_INFO my_charset_utf8_slovak_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -9042,6 +9073,7 @@ CHARSET_INFO my_charset_utf8_spanish2_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -9072,6 +9104,7 @@ CHARSET_INFO my_charset_utf8_roman_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
@@ -9102,6 +9135,7 @@ CHARSET_INFO my_charset_utf8_persian_uca_ci=
3, /* mbmaxlen */
9, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_any_uca_handler
};
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 408e511d2e8..41ab055d2de 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -1621,6 +1621,7 @@ CHARSET_INFO my_charset_ucs2_general_ci=
2, /* mbmaxlen */
0, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_general_ci_handler
};
@@ -1651,6 +1652,7 @@ CHARSET_INFO my_charset_ucs2_bin=
2, /* mbmaxlen */
0, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_ucs2_handler,
&my_collation_ucs2_bin_handler
};
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
index 3f934ebd9ce..57ca2de2852 100644
--- a/strings/ctype-ujis.c
+++ b/strings/ctype-ujis.c
@@ -8576,6 +8576,7 @@ CHARSET_INFO my_charset_ujis_japanese_ci=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_ci_handler
};
@@ -8607,6 +8608,7 @@ CHARSET_INFO my_charset_ujis_bin=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_handler,
&my_collation_mb_bin_handler
};
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 2b5f5883abf..88b6b7d5c86 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -2579,6 +2579,7 @@ CHARSET_INFO my_charset_utf8_general_ci=
3, /* mbmaxlen */
0, /* min_sort_char */
0xFFFF, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_ci_handler
};
@@ -2610,6 +2611,7 @@ CHARSET_INFO my_charset_utf8_bin=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_mb_bin_handler
};
@@ -2779,6 +2781,7 @@ CHARSET_INFO my_charset_utf8_general_cs=
3, /* mbmaxlen */
0, /* min_sort_char */
255, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_utf8_handler,
&my_collation_cs_handler
};
diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c
index b840a58a499..c6b396658d4 100644
--- a/strings/ctype-win1250ch.c
+++ b/strings/ctype-win1250ch.c
@@ -662,6 +662,7 @@ CHARSET_INFO my_charset_cp1250_czech_ci =
1, /* mbmaxlen */
0, /* min_sort_char */
0, /* max_sort_char */
+ 0, /* escape_with_backslash_is_dangerous */
&my_charset_8bit_handler,
&my_collation_czech_ci_handler
};
diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s
index fcc57810224..1840bab3f47 100644
--- a/strings/longlong2str-x86.s
+++ b/strings/longlong2str-x86.s
@@ -16,26 +16,26 @@
# Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
# Some set sequences are optimized for pentuimpro II
- .file "longlong2str.s"
- .version "1.01"
+ .file "longlong2str-x86.s"
+ .version "1.02"
.text
.align 4
-.globl longlong2str
- .type longlong2str,@function
+.globl longlong2str_with_dig_vector
+ .type longlong2str_with_dig_vector,@function
-longlong2str:
+longlong2str_with_dig_vector:
subl $80,%esp
pushl %ebp
pushl %esi
pushl %edi
pushl %ebx
movl 100(%esp),%esi # Lower part of val
- movl 104(%esp),%ebp # Higher part of val
- movl 108(%esp),%edi # get dst
movl 112(%esp),%ebx # Radix
+ movl 104(%esp),%ebp # Higher part of val
movl %ebx,%eax
+ movl 108(%esp),%edi # get dst
testl %eax,%eax
jge .L144
@@ -69,6 +69,8 @@ longlong2str:
.L150:
leal 92(%esp),%ecx # End of buffer
+ movl %edi, 108(%esp) # Store possible modified dest
+ movl 116(%esp), %edi # dig_vec_upper
jmp .L155
.align 4
@@ -83,7 +85,7 @@ longlong2str:
divl %ebx
decl %ecx
movl %eax,%esi # quotent in ebp:esi
- movb _dig_vec_upper(%edx),%al # al is faster than dl
+ movb (%edx,%edi),%al # al is faster than dl
movb %al,(%ecx) # store value in buff
.align 4
.L155:
@@ -91,20 +93,22 @@ longlong2str:
ja .L153
testl %esi,%esi # rest value
jl .L153
- je .L10_mov # Ready
+ je .L160 # Ready
movl %esi,%eax
- movl $_dig_vec_upper,%ebp
.align 4
.L154: # Do rest with integer precision
cltd
divl %ebx
decl %ecx
- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
+ movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36
testl %eax,%eax
movb %dl,(%ecx)
jne .L154
+.L160:
+ movl 108(%esp),%edi # get dst
+
.L10_mov:
movl %ecx,%esi
leal 92(%esp),%ecx # End of buffer
@@ -129,7 +133,7 @@ longlong2str:
jmp .L165
.Lfe3:
- .size longlong2str,.Lfe3-longlong2str
+ .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector
#
# This is almost equal to the above, except that we can do the final
@@ -137,9 +141,6 @@ longlong2str:
#
.align 4
-.Ltmp:
- .long 0xcccccccd
- .align 4
.globl longlong10_to_str
.type longlong10_to_str,@function
@@ -202,8 +203,8 @@ longlong10_to_str:
# The following code uses some tricks to change division by 10 to
# multiplication and shifts
- movl .Ltmp,%esi # set %esi to 0xcccccccd
-
+ movl $0xcccccccd,%esi
+
.L10_40:
movl %ebx,%eax
mull %esi
diff --git a/strings/longlong2str_asm.c b/strings/longlong2str_asm.c
new file mode 100644
index 00000000000..e38a8328b91
--- /dev/null
+++ b/strings/longlong2str_asm.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; 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 */
+
+/*
+ Wrapper for longlong2str.s
+
+ We need this because the assembler code can't access the local variable
+ _dig_vector in a portable manner.
+*/
+
+#include <my_global.h>
+#include "m_string.h"
+
+extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix,
+ const char *dig_vector);
+
+char *longlong2str(longlong val,char *dst,int radix)
+{
+ return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper);
+}
diff --git a/strings/my_strtoll10-x86.s b/strings/my_strtoll10-x86.s
index c04384667a7..1d8b8f2bbce 100644
--- a/strings/my_strtoll10-x86.s
+++ b/strings/my_strtoll10-x86.s
@@ -17,21 +17,8 @@
# For documentation, check my_strtoll.c
.file "my_strtoll10-x86.s"
- .version "01.01"
-.data
- .align 32
- .type lfactor,@object
- .size lfactor,36
-lfactor:
- .long 1
- .long 10
- .long 100
- .long 1000
- .long 10000
- .long 100000
- .long 1000000
- .long 10000000
- .long 100000000
+ .version "01.02"
+
.text
.align 4
@@ -209,14 +196,16 @@ my_strtoll10:
jne .L500
cmpl -36(%ebp),%esi # Test if string is less than 18 digits
jne .Lend_i_and_j
- jmp .Lend3 # 18 digit string
+.L499:
+ movl $1000000000,%eax
+ jmp .Lgot_factor # 18 digit string
# Handle the possible next to last digit and store in ecx
.L500:
movb (%esi),%al
addb $-48,%al
cmpb $9,%al
- ja .Lend3
+ ja .L499 # 18 digit string
incl %esi
movzbl %al,%ecx
@@ -315,14 +304,41 @@ my_strtoll10:
.Lend_i_and_j:
movl %esi,%ecx
subl -12(%ebp),%ecx # ecx= number of digits in second part
- movl lfactor(,%ecx,4),%eax
- jmp .L523
- # Return -8(%ebp) * $1000000000 + edi
+ # Calculate %eax= 10 ** %cl, where %cl <= 8
+ # With an array one could do this with:
+ # movl 10_factor_table(,%ecx,4),%eax
+ # We calculate the table here to avoid problems in
+ # position independent code (gcc -pic)
+
+ cmpb $3,%cl
+ ja .L4_to_8
+ movl $1000, %eax
+ je .Lgot_factor # %cl=3, eax= 1000
+ movl $10, %eax
+ cmpb $1,%cl # %cl is here 0 - 2
+ je .Lgot_factor # %cl=1, eax= 10
+ movl $100, %eax
+ ja .Lgot_factor # %cl=2, eax=100
+ movl $1, %eax
+ jmp .Lgot_factor # %cl=0, eax=1
+
+.L4_to_8: # %cl is here 4-8
+ cmpb $5,%cl
+ movl $100000, %eax
+ je .Lgot_factor # %cl=5, eax=100000
+ movl $10000, %eax
+ jbe .Lgot_factor # %cl=4, eax=10000
+ movl $10000000, %eax
+ cmpb $7,%cl
+ je .Lgot_factor # %cl=7, eax=10000000
+ movl $100000000, %eax
+ ja .Lgot_factor # %cl=8, eax=100000000
+ movl $1000000, %eax # %cl=6, eax=1000000
+
+ # Return -8(%ebp) * %eax + edi
.p2align 4,,7
-.Lend3:
- movl $1000000000,%eax
-.L523:
+.Lgot_factor:
mull -8(%ebp)
addl %edi,%eax
adcl $0,%edx
diff --git a/support-files/MacOSX/Info.plist.sh b/support-files/MacOSX/Info.plist.sh
index f14902ff379..fdfb0c7a17c 100644
--- a/support-files/MacOSX/Info.plist.sh
+++ b/support-files/MacOSX/Info.plist.sh
@@ -9,11 +9,7 @@
<key>CFBundleName</key>
<string>MySQL</string>
<key>CFBundleShortVersionString</key>
- <string>@VERSION@</string>
- <key>IFMajorVersion</key>
- <integer>4</integer>
- <key>IFMinorVersion</key>
- <integer>0</integer>
+ <string>@MYSQL_NO_DASH_VERSION@</string>
<key>IFPkgFlagAllowBackRev</key>
<false/>
<key>IFPkgFlagAuthorizationAction</key>
diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am
index 86773f12339..ea99c46389d 100644
--- a/support-files/MacOSX/Makefile.am
+++ b/support-files/MacOSX/Makefile.am
@@ -20,19 +20,25 @@
EXTRA_DIST = Info.plist.sh \
Description.plist.sh \
StartupParameters.plist.sh \
- postinstall.sh \
- preinstall.sh \
+ postflight.sh \
+ preflight.sh \
ReadMe.txt \
MySQLCOM \
StartupItem.Description.plist \
StartupItem.Info.plist \
StartupItem.postinstall
+noinst_DATA = Info.plist \
+ Description.plist \
+ StartupParameters.plist \
+ postflight \
+ preflight
+
CLEANFILES = Info.plist \
Description.plist \
StartupParameters.plist \
- postinstall \
- preinstall
+ postflight \
+ preflight
SUFFIXES = .sh
@@ -41,6 +47,7 @@ SUFFIXES = .sh
@SED@ \
-e 's!@''prefix''@!$(prefix)!g' \
-e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
-e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \
-e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \
$< > $@-t
diff --git a/support-files/MacOSX/postinstall.sh b/support-files/MacOSX/postflight.sh
index ff921d3fee9..451eb65e0d7 100644
--- a/support-files/MacOSX/postinstall.sh
+++ b/support-files/MacOSX/postflight.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# postinstall - this script will be executed after the MySQL PKG
+# postflight - this script will be executed after the MySQL PKG
# installation has been performed.
#
# This script will install the MySQL privilege tables using the
diff --git a/support-files/MacOSX/preinstall.sh b/support-files/MacOSX/preflight.sh
index 62772573c46..700d0640a9e 100644
--- a/support-files/MacOSX/preinstall.sh
+++ b/support-files/MacOSX/preflight.sh
@@ -1,10 +1,10 @@
#!/bin/sh
#
-# preinstall - this script will be executed before the MySQL PKG
+# preflight - this script will be executed before the MySQL PKG
# installation will be performed.
#
# If this package has been compiled with a prefix ending with "mysql" (e.g.
-# /usr/local/mysql or /opt/mysql), it will rename any previosuly existing
+# /usr/local/mysql or /opt/mysql), it will rename any previously existing
# directory with this name before installing the new package (which includes
# a symlink named "mysql", pointing to the newly installed directory, which
# is named mysql-<version>)
diff --git a/support-files/Makefile.am b/support-files/Makefile.am
index d83dd8ee74d..972d1dc7038 100644
--- a/support-files/Makefile.am
+++ b/support-files/Makefile.am
@@ -43,6 +43,9 @@ pkgdata_DATA = my-small.cnf \
pkgdata_SCRIPTS = mysql.server
+noinst_DATA = mysql-@VERSION@.spec \
+ MySQL-shared-compat.spec
+
CLEANFILES = my-small.cnf \
my-medium.cnf \
my-large.cnf \
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 2a01c7dfb40..ac19819f9af 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -308,7 +308,7 @@ BuildMySQL "--enable-shared \
--with-comment=\"MySQL Community Edition - Max (GPL)\" \
--with-server-suffix='-Max'"
-make test
+make test-force || true
# Save mysqld-max
mv sql/mysqld sql/mysqld-max
@@ -360,7 +360,7 @@ BuildMySQL "--disable-shared \
--without-openssl"
nm --numeric-sort sql/mysqld > sql/mysqld.sym
-make test
+make test-force || true
%install
RBR=$RPM_BUILD_ROOT
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ca7f04c91f9..131f8b1b625 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,8 +42,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
LIBS = @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ \
$(top_builddir)/libmysql/libmysqlclient.la
-mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) \
- $(top_builddir)/mysys/libmysys.a
+mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS)
mysql_client_test_SOURCES= mysql_client_test.c $(yassl_dummy_link_fix)
insert_test_SOURCES= insert_test.c $(yassl_dummy_link_fix)
select_test_SOURCES= select_test.c $(yassl_dummy_link_fix)
diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl
index a1c55ac4c11..567cfafa176 100644
--- a/tests/fork_big2.pl
+++ b/tests/fork_big2.pl
@@ -300,7 +300,7 @@ sub test_select
#
# Do big select count(distinct..) over the table
-#
+#
sub test_select_count
{
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 53708a7a741..4f1e6a72b91 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -7195,7 +7195,7 @@ static void test_prepare_grant()
}
}
-#endif
+#endif /* EMBEDDED_LIBRARY */
/*
Test a crash when invalid/corrupted .frm is used in the
@@ -13893,10 +13893,10 @@ static void test_bug12001()
MYSQL *mysql_local;
MYSQL_RES *result;
const char *query= "DROP TABLE IF EXISTS test_table;"
- "CREATE TABLE test_table(id INT);"
- "INSERT INTO test_table VALUES(10);"
- "UPDATE test_table SET id=20 WHERE id=10;"
- "SELECT * FROM test_table;"
+ "CREATE TABLE test_table(id INT);"
+ "INSERT INTO test_table VALUES(10);"
+ "UPDATE test_table SET id=20 WHERE id=10;"
+ "SELECT * FROM test_table;"
"INSERT INTO non_existent_table VALUES(11);";
int rc, res;
@@ -13911,7 +13911,9 @@ static void test_bug12001()
/* Create connection that supports multi statements */
if (!mysql_real_connect(mysql_local, opt_host, opt_user,
opt_password, current_db, opt_port,
- opt_unix_socket, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS)) {
+ opt_unix_socket, CLIENT_MULTI_STATEMENTS |
+ CLIENT_MULTI_RESULTS))
+ {
fprintf(stdout, "\n mysql_real_connect() failed");
exit(1);
}
@@ -13919,12 +13921,16 @@ static void test_bug12001()
rc= mysql_query(mysql_local, query);
myquery(rc);
- do {
- if (mysql_field_count(mysql_local) && (result= mysql_use_result(mysql_local))) {
- mysql_free_result(result);
+ do
+ {
+ if (mysql_field_count(mysql_local) &&
+ (result= mysql_use_result(mysql_local)))
+ {
+ mysql_free_result(result);
}
- } while (!(res= mysql_next_result(mysql_local)));
-
+ }
+ while (!(res= mysql_next_result(mysql_local)));
+
rc= mysql_query(mysql_local, "DROP TABLE IF EXISTS test_table");
myquery(rc);
@@ -13932,6 +13938,341 @@ static void test_bug12001()
DIE_UNLESS(res==1);
}
+
+/* Bug#11909: wrong metadata if fetching from two cursors */
+
+static void test_bug11909()
+{
+ MYSQL_STMT *stmt1, *stmt2;
+ MYSQL_BIND bind[7];
+ int rc;
+ char firstname[20], midinit[20], lastname[20], workdept[20];
+ ulong firstname_len, midinit_len, lastname_len, workdept_len;
+ uint32 empno;
+ double salary;
+ float bonus;
+ const char *stmt_text;
+
+ myheader("test_bug11909");
+
+ stmt_text= "drop table if exists t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "create table t1 ("
+ " empno int(11) not null, firstname varchar(20) not null,"
+ " midinit varchar(20) not null, lastname varchar(20) not null,"
+ " workdept varchar(6) not null, salary double not null,"
+ " bonus float not null, primary key (empno)"
+ ") default charset=latin1 collate=latin1_bin";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "insert into t1 values "
+ "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), "
+ "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800),"
+ "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800),"
+ "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
+ "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ /* ****** Begin of trace ****** */
+
+ stmt1= open_cursor("SELECT empno, firstname, midinit, lastname,"
+ "workdept, salary, bonus FROM t1");
+
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type= MYSQL_TYPE_LONG;
+ bind[0].buffer= (void*) &empno;
+
+ bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+ bind[1].buffer= (void*) firstname;
+ bind[1].buffer_length= sizeof(firstname);
+ bind[1].length= &firstname_len;
+
+ bind[2].buffer_type= MYSQL_TYPE_VAR_STRING;
+ bind[2].buffer= (void*) midinit;
+ bind[2].buffer_length= sizeof(midinit);
+ bind[2].length= &midinit_len;
+
+ bind[3].buffer_type= MYSQL_TYPE_VAR_STRING;
+ bind[3].buffer= (void*) lastname;
+ bind[3].buffer_length= sizeof(lastname);
+ bind[3].length= &lastname_len;
+
+ bind[4].buffer_type= MYSQL_TYPE_VAR_STRING;
+ bind[4].buffer= (void*) workdept;
+ bind[4].buffer_length= sizeof(workdept);
+ bind[4].length= &workdept_len;
+
+ bind[5].buffer_type= MYSQL_TYPE_DOUBLE;
+ bind[5].buffer= (void*) &salary;
+
+ bind[6].buffer_type= MYSQL_TYPE_FLOAT;
+ bind[6].buffer= (void*) &bonus;
+ rc= mysql_stmt_bind_result(stmt1, bind);
+ check_execute(stmt1, rc);
+
+ rc= mysql_stmt_execute(stmt1);
+ check_execute(stmt1, rc);
+
+ rc= mysql_stmt_fetch(stmt1);
+ DIE_UNLESS(rc == 0);
+ DIE_UNLESS(empno == 10);
+ DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0);
+ DIE_UNLESS(strcmp(midinit, "I") == 0);
+ DIE_UNLESS(strcmp(lastname, "HAAS") == 0);
+ DIE_UNLESS(strcmp(workdept, "A00") == 0);
+ DIE_UNLESS(salary == (double) 52750.0);
+ DIE_UNLESS(bonus == (float) 1000.0);
+
+ stmt2= open_cursor("SELECT empno, firstname FROM t1");
+ rc= mysql_stmt_bind_result(stmt2, bind);
+ check_execute(stmt2, rc);
+
+ rc= mysql_stmt_execute(stmt2);
+ check_execute(stmt2, rc);
+
+ rc= mysql_stmt_fetch(stmt2);
+ DIE_UNLESS(rc == 0);
+
+ DIE_UNLESS(empno == 10);
+ DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0);
+
+ rc= mysql_stmt_reset(stmt2);
+ check_execute(stmt2, rc);
+
+ /* ERROR: next statement should return 0 */
+
+ rc= mysql_stmt_fetch(stmt1);
+ DIE_UNLESS(rc == 0);
+
+ mysql_stmt_close(stmt1);
+ mysql_stmt_close(stmt2);
+ rc= mysql_rollback(mysql);
+ myquery(rc);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+/* Cursors: opening a cursor to a compilicated query with ORDER BY */
+
+static void test_bug11901()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[2];
+ int rc;
+ char workdept[20];
+ ulong workdept_len;
+ uint32 empno;
+ const char *stmt_text;
+
+ myheader("test_bug11901");
+
+ stmt_text= "drop table if exists t1, t2";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "create table t1 ("
+ " empno int(11) not null, firstname varchar(20) not null,"
+ " midinit varchar(20) not null, lastname varchar(20) not null,"
+ " workdept varchar(6) not null, salary double not null,"
+ " bonus float not null, primary key (empno), "
+ " unique key (workdept, empno) "
+ ") default charset=latin1 collate=latin1_bin";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "insert into t1 values "
+ "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000),"
+ "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), "
+ "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), "
+ "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), "
+ "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), "
+ "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), "
+ "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), "
+ "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), "
+ "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), "
+ "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), "
+ "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), "
+ "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), "
+ "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), "
+ "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), "
+ "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), "
+ "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), "
+ "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), "
+ "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), "
+ "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), "
+ "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), "
+ "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), "
+ "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), "
+ "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), "
+ "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), "
+ "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), "
+ "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), "
+ "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), "
+ "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), "
+ "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), "
+ "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), "
+ "(330, 'WING', '', 'LEE', 'E21', 25370, 500), "
+ "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)";
+
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "create table t2 ("
+ " deptno varchar(6) not null, deptname varchar(20) not null,"
+ " mgrno int(11) not null, location varchar(20) not null,"
+ " admrdept varchar(6) not null, refcntd int(11) not null,"
+ " refcntu int(11) not null, primary key (deptno)"
+ ") default charset=latin1 collate=latin1_bin";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "insert into t2 values "
+ "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), "
+ "('B01', 'PLANNING', 20, '', 'A00', 0, 0), "
+ "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), "
+ "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0),"
+ "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), "
+ "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), "
+ "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), "
+ "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), "
+ "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ /* ****** Begin of trace ****** */
+
+ stmt= open_cursor("select t1.empno, t1.workdept "
+ "from (t1 left join t2 on t2.deptno = t1.workdept) "
+ "where t2.deptno in "
+ " (select t2.deptno "
+ " from (t1 left join t2 on t2.deptno = t1.workdept) "
+ " where t1.empno = ?) "
+ "order by 1");
+ bzero(bind, sizeof(bind));
+
+ bind[0].buffer_type= MYSQL_TYPE_LONG;
+ bind[0].buffer= &empno;
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
+ bind[1].buffer= (void*) workdept;
+ bind[1].buffer_length= sizeof(workdept);
+ bind[1].length= &workdept_len;
+
+ rc= mysql_stmt_bind_result(stmt, bind);
+ check_execute(stmt, rc);
+
+ empno= 10;
+ /* ERROR: next statement causes a server crash */
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "drop table t1, t2");
+ myquery(rc);
+}
+
+/* Bug#12243: multiple cursors, crash in a fetch after commit. */
+
+static void test_bug12243()
+{
+ MYSQL_STMT *stmt1, *stmt2;
+ int rc;
+ const char *stmt_text;
+ ulong type;
+
+ myheader("test_bug12243");
+
+ if (! have_innodb)
+ {
+ if (!opt_silent)
+ printf("This test requires InnoDB.\n");
+ return;
+ }
+
+ /* create tables */
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (a int) engine=InnoDB");
+ rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)");
+ myquery(rc);
+ mysql_autocommit(mysql, FALSE);
+ /* create statement */
+ stmt1= mysql_stmt_init(mysql);
+ stmt2= mysql_stmt_init(mysql);
+ type= (ulong) CURSOR_TYPE_READ_ONLY;
+ mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+ mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+
+ stmt_text= "select a from t1";
+
+ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+ check_execute(stmt1, rc);
+ rc= mysql_stmt_execute(stmt1);
+ check_execute(stmt1, rc);
+ rc= mysql_stmt_fetch(stmt1);
+ check_execute(stmt1, rc);
+
+ rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text));
+ check_execute(stmt2, rc);
+ rc= mysql_stmt_execute(stmt2);
+ check_execute(stmt2, rc);
+ rc= mysql_stmt_fetch(stmt2);
+ check_execute(stmt2, rc);
+
+ rc= mysql_stmt_close(stmt1);
+ check_execute(stmt1, rc);
+ rc= mysql_commit(mysql);
+ myquery(rc);
+ rc= mysql_stmt_fetch(stmt2);
+ check_execute(stmt2, rc);
+
+ mysql_stmt_close(stmt2);
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+ mysql_autocommit(mysql, TRUE); /* restore default */
+}
+
+/*
+ Bug#11718: query with function, join and order by returns wrong type
+*/
+
+static void test_bug11718()
+{
+ MYSQL_RES *res;
+ int rc;
+ const char *query= "select str_to_date(concat(f3),'%Y%m%d') from t1,t2 "
+ "where f1=f2 order by f1";
+
+ myheader("test_bug11718");
+
+ rc= mysql_query(mysql, "drop table if exists t1, t2");
+ myquery(rc);
+ rc= mysql_query(mysql, "create table t1 (f1 int)");
+ myquery(rc);
+ rc= mysql_query(mysql, "create table t2 (f2 int, f3 numeric(8))");
+ myquery(rc);
+ rc= mysql_query(mysql, "insert into t1 values (1), (2)");
+ myquery(rc);
+ rc= mysql_query(mysql, "insert into t2 values (1,20050101), (2,20050202)");
+ myquery(rc);
+ rc= mysql_query(mysql, query);
+ myquery(rc);
+ res = mysql_store_result(mysql);
+
+ if (!opt_silent)
+ printf("return type: %s", (res->fields[0].type == MYSQL_TYPE_DATE)?"DATE":
+ "not DATE");
+ DIE_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE);
+ rc= mysql_query(mysql, "drop table t1, t2");
+ myquery(rc);
+}
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -14178,6 +14519,10 @@ static struct my_tests_st my_tests[]= {
{ "test_bug11037", test_bug11037 },
{ "test_bug10760", test_bug10760 },
{ "test_bug12001", test_bug12001 },
+ { "test_bug11718", test_bug11718 },
+ { "test_bug11909", test_bug11909 },
+ { "test_bug11901", test_bug11901 },
+ { "test_bug12243", test_bug12243 },
{ 0, 0 }
};