summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/SETUP.sh7
-rwxr-xr-xBUILD/autorun.sh10
-rwxr-xr-xBUILD/compile-pentium-debug-max-no-embedded2
-rw-r--r--BitKeeper/etc/config2
-rw-r--r--Docs/Makefile.am10
-rw-r--r--Docs/README.1st76
-rwxr-xr-xDocs/Support/generate-flag-images31
-rwxr-xr-xDocs/Support/generate-text-files.pl2
-rw-r--r--Makefile.am5
-rw-r--r--VC++Files/libmysql/libmysql.dsp4
-rw-r--r--VC++Files/sql/mysqld.dsp2
-rw-r--r--VC++Files/tests/mysql_client_test.dsp8
-rw-r--r--client/Makefile.am4
-rw-r--r--client/mysql.cc3
-rw-r--r--client/mysqldump.c295
-rw-r--r--client/mysqltest.c40
-rw-r--r--cmd-line-utils/libedit/Makefile.am3
-rw-r--r--cmd-line-utils/libedit/chared.c4
-rw-r--r--cmd-line-utils/readline/Makefile.am3
-rw-r--r--config/ac-macros/misc.m456
-rw-r--r--configure.in29
-rw-r--r--dbug/Makefile.am2
-rw-r--r--extra/Makefile.am5
-rw-r--r--extra/yassl/include/yassl_types.hpp3
-rw-r--r--extra/yassl/src/Makefile.am1
-rw-r--r--extra/yassl/src/buffer.cpp1
-rw-r--r--extra/yassl/src/cert_wrapper.cpp1
-rw-r--r--extra/yassl/src/crypto_wrapper.cpp4
-rw-r--r--extra/yassl/src/lock.cpp1
-rw-r--r--extra/yassl/src/log.cpp2
-rw-r--r--extra/yassl/src/socket_wrapper.cpp1
-rw-r--r--extra/yassl/src/template_instnt.cpp74
-rw-r--r--extra/yassl/src/timer.cpp1
-rw-r--r--extra/yassl/src/yassl_error.cpp1
-rw-r--r--extra/yassl/src/yassl_int.cpp43
-rw-r--r--extra/yassl/taocrypt/include/runtime.hpp4
-rw-r--r--extra/yassl/taocrypt/include/types.hpp42
-rw-r--r--extra/yassl/taocrypt/src/Makefile.am1
-rw-r--r--extra/yassl/taocrypt/src/aestables.cpp1
-rw-r--r--extra/yassl/taocrypt/src/algebra.cpp4
-rw-r--r--extra/yassl/taocrypt/src/arc4.cpp1
-rw-r--r--extra/yassl/taocrypt/src/coding.cpp1
-rw-r--r--extra/yassl/taocrypt/src/dh.cpp1
-rw-r--r--extra/yassl/taocrypt/src/dsa.cpp1
-rw-r--r--extra/yassl/taocrypt/src/file.cpp1
-rw-r--r--extra/yassl/taocrypt/src/integer.cpp7
-rw-r--r--extra/yassl/taocrypt/src/misc.cpp27
-rw-r--r--extra/yassl/taocrypt/src/random.cpp1
-rw-r--r--extra/yassl/taocrypt/src/rsa.cpp1
-rw-r--r--extra/yassl/taocrypt/src/template_instnt.cpp32
-rw-r--r--heap/Makefile.am2
-rw-r--r--heap/hp_hash.c4
-rw-r--r--include/config-netware.h10
-rw-r--r--include/my_base.h1
-rw-r--r--include/my_bitmap.h2
-rw-r--r--include/my_global.h14
-rw-r--r--include/my_sys.h4
-rw-r--r--include/mysql.h16
-rw-r--r--include/mysql_com.h15
-rw-r--r--innobase/btr/btr0btr.c174
-rw-r--r--innobase/btr/btr0cur.c264
-rw-r--r--innobase/btr/btr0pcur.c66
-rw-r--r--innobase/btr/btr0sea.c191
-rw-r--r--innobase/buf/buf0buf.c40
-rw-r--r--innobase/buf/buf0flu.c6
-rw-r--r--innobase/buf/buf0lru.c6
-rw-r--r--innobase/buf/buf0rea.c8
-rw-r--r--innobase/configure.in7
-rw-r--r--innobase/data/data0data.c2
-rw-r--r--innobase/data/data0type.c4
-rw-r--r--innobase/dict/dict0boot.c9
-rw-r--r--innobase/dict/dict0crea.c2
-rw-r--r--innobase/dict/dict0dict.c23
-rw-r--r--innobase/dict/dict0mem.c1
-rw-r--r--innobase/fil/fil0fil.c29
-rw-r--r--innobase/fsp/fsp0fsp.c4
-rw-r--r--innobase/ibuf/ibuf0ibuf.c54
-rw-r--r--innobase/include/btr0btr.h11
-rw-r--r--innobase/include/btr0btr.ic4
-rw-r--r--innobase/include/btr0cur.h2
-rw-r--r--innobase/include/btr0cur.ic4
-rw-r--r--innobase/include/buf0buf.h20
-rw-r--r--innobase/include/buf0buf.ic29
-rw-r--r--innobase/include/buf0lru.h2
-rw-r--r--innobase/include/data0type.h2
-rw-r--r--innobase/include/data0type.ic4
-rw-r--r--innobase/include/dyn0dyn.h2
-rw-r--r--innobase/include/dyn0dyn.ic7
-rw-r--r--innobase/include/lock0lock.h19
-rw-r--r--innobase/include/log0log.h4
-rw-r--r--innobase/include/mach0data.h21
-rw-r--r--innobase/include/mach0data.ic31
-rw-r--r--innobase/include/mem0mem.ic2
-rw-r--r--innobase/include/mtr0log.h14
-rw-r--r--innobase/include/mtr0mtr.h6
-rw-r--r--innobase/include/os0file.h15
-rw-r--r--innobase/include/page0cur.h14
-rw-r--r--innobase/include/page0cur.ic22
-rw-r--r--innobase/include/page0page.h68
-rw-r--r--innobase/include/page0page.ic270
-rw-r--r--innobase/include/read0read.ic9
-rw-r--r--innobase/include/rem0rec.h59
-rw-r--r--innobase/include/rem0rec.ic122
-rw-r--r--innobase/include/row0mysql.h35
-rw-r--r--innobase/include/row0sel.ic2
-rw-r--r--innobase/include/row0upd.ic2
-rw-r--r--innobase/include/srv0srv.h1
-rw-r--r--innobase/include/sync0rw.ic39
-rw-r--r--innobase/include/trx0rseg.ic4
-rw-r--r--innobase/include/trx0trx.h63
-rw-r--r--innobase/include/trx0trx.ic56
-rw-r--r--innobase/include/univ.i26
-rw-r--r--innobase/include/ut0dbg.h119
-rw-r--r--innobase/include/ut0rnd.ic6
-rw-r--r--innobase/lock/lock0lock.c404
-rw-r--r--innobase/log/log0log.c60
-rw-r--r--innobase/log/log0recv.c65
-rw-r--r--innobase/mtr/mtr0log.c24
-rw-r--r--innobase/mtr/mtr0mtr.c12
-rw-r--r--innobase/os/os0file.c89
-rw-r--r--innobase/page/page0cur.c158
-rw-r--r--innobase/page/page0page.c151
-rw-r--r--innobase/rem/rem0cmp.c99
-rw-r--r--innobase/rem/rem0rec.c242
-rw-r--r--innobase/row/row0ins.c116
-rw-r--r--innobase/row/row0mysql.c158
-rw-r--r--innobase/row/row0purge.c4
-rw-r--r--innobase/row/row0row.c10
-rw-r--r--innobase/row/row0sel.c448
-rw-r--r--innobase/row/row0umod.c15
-rw-r--r--innobase/row/row0undo.c2
-rw-r--r--innobase/row/row0upd.c27
-rw-r--r--innobase/row/row0vers.c18
-rw-r--r--innobase/srv/srv0srv.c17
-rw-r--r--innobase/srv/srv0start.c5
-rw-r--r--innobase/sync/sync0sync.c4
-rw-r--r--innobase/trx/trx0rec.c12
-rw-r--r--innobase/trx/trx0roll.c2
-rw-r--r--innobase/trx/trx0trx.c12
-rw-r--r--innobase/trx/trx0undo.c32
-rw-r--r--innobase/ut/ut0dbg.c65
-rw-r--r--libmysql/Makefile.am4
-rw-r--r--libmysql/libmysql.c106
-rw-r--r--libmysql/libmysql.def1
-rw-r--r--libmysql_r/Makefile.am4
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--libmysqld/examples/Makefile.am4
-rw-r--r--libmysqld/lib_sql.cc4
-rw-r--r--myisam/Makefile.am2
-rw-r--r--myisam/ft_boolean_search.c2
-rw-r--r--myisam/mi_create.c3
-rw-r--r--myisam/mi_open.c2
-rw-r--r--myisam/mi_packrec.c15
-rw-r--r--myisam/mi_unique.c21
-rw-r--r--myisam/myisampack.c1280
-rw-r--r--myisammrg/Makefile.am2
-rw-r--r--mysql-test/Makefile.am15
-rw-r--r--mysql-test/README13
-rw-r--r--mysql-test/include/not_openssl.inc4
-rw-r--r--mysql-test/include/ps_create.inc2
-rw-r--r--mysql-test/lib/init_db.sql2
-rw-r--r--mysql-test/lib/mtr_cases.pl128
-rw-r--r--mysql-test/lib/mtr_misc.pl53
-rw-r--r--mysql-test/lib/mtr_report.pl7
-rwxr-xr-xmysql-test/mysql-test-run.pl356
-rw-r--r--mysql-test/mysql-test-run.sh5
-rw-r--r--mysql-test/mysql_test_run_new.c1
-rw-r--r--mysql-test/r/alias.result2
-rw-r--r--mysql-test/r/archive.result1220
-rw-r--r--mysql-test/r/case.result15
-rw-r--r--mysql-test/r/client_xml.result2
-rw-r--r--mysql-test/r/ctype_ucs.result30
-rw-r--r--mysql-test/r/ctype_utf8.result45
-rw-r--r--mysql-test/r/fulltext.result2
-rw-r--r--mysql-test/r/fulltext_order_by.result74
-rw-r--r--mysql-test/r/func_date_add.result2
-rw-r--r--mysql-test/r/func_des_encrypt.result3
-rw-r--r--mysql-test/r/func_encrypt.result44
-rw-r--r--mysql-test/r/func_encrypt_nossl.result98
-rw-r--r--mysql-test/r/func_str.result81
-rw-r--r--mysql-test/r/func_time.result2
-rw-r--r--mysql-test/r/grant.result118
-rw-r--r--mysql-test/r/group_by.result47
-rw-r--r--mysql-test/r/heap.result8
-rw-r--r--mysql-test/r/heap_hash.result23
-rw-r--r--mysql-test/r/index_merge.result4
-rw-r--r--mysql-test/r/index_merge_innodb.result11
-rw-r--r--mysql-test/r/information_schema.result10
-rw-r--r--mysql-test/r/innodb.result24
-rw-r--r--mysql-test/r/insert_select.result45
-rw-r--r--mysql-test/r/insert_update.result12
-rw-r--r--mysql-test/r/lowercase_table2.result3
-rw-r--r--mysql-test/r/mysqldump.result210
-rw-r--r--mysql-test/r/ndb_autodiscover.result6
-rw-r--r--mysql-test/r/ndb_insert.result16
-rw-r--r--mysql-test/r/ndb_subquery.result19
-rw-r--r--mysql-test/r/not_openssl.require2
-rw-r--r--mysql-test/r/olap.result22
-rw-r--r--mysql-test/r/ps.result127
-rw-r--r--mysql-test/r/ps_1general.result6
-rw-r--r--mysql-test/r/ps_2myisam.result22
-rw-r--r--mysql-test/r/ps_3innodb.result22
-rw-r--r--mysql-test/r/ps_4heap.result18
-rw-r--r--mysql-test/r/ps_5merge.result48
-rw-r--r--mysql-test/r/ps_6bdb.result22
-rw-r--r--mysql-test/r/ps_7ndb.result22
-rw-r--r--mysql-test/r/query_cache.result91
-rw-r--r--mysql-test/r/range.result108
-rw-r--r--mysql-test/r/rpl_deadlock.result2
-rw-r--r--mysql-test/r/rpl_innodb.result37
-rw-r--r--mysql-test/r/rpl_multi_update3.result124
-rw-r--r--mysql-test/r/rpl_sp.result10
-rw-r--r--mysql-test/r/rpl_trunc_binlog.result17
-rw-r--r--mysql-test/r/select.result275
-rw-r--r--mysql-test/r/show_check.result21
-rw-r--r--mysql-test/r/sp-error.result156
-rw-r--r--mysql-test/r/sp-goto.result205
-rw-r--r--mysql-test/r/sp-security.result42
-rw-r--r--mysql-test/r/sp-threads.result9
-rw-r--r--mysql-test/r/sp.result383
-rw-r--r--mysql-test/r/sql_mode.result61
-rw-r--r--mysql-test/r/strict.result10
-rw-r--r--mysql-test/r/subselect.result29
-rw-r--r--mysql-test/r/system_mysql_db.result10
-rw-r--r--mysql-test/r/trigger.result102
-rw-r--r--mysql-test/r/type_bit.result87
-rw-r--r--mysql-test/r/type_blob.result15
-rw-r--r--mysql-test/r/type_decimal.result27
-rw-r--r--mysql-test/r/type_float.result14
-rw-r--r--mysql-test/r/type_newdecimal.result59
-rw-r--r--mysql-test/r/type_timestamp.result8
-rw-r--r--mysql-test/r/update.result4
-rw-r--r--mysql-test/r/variables.result4
-rw-r--r--mysql-test/r/view.result310
-rw-r--r--mysql-test/r/view_grant.result2
-rw-r--r--mysql-test/std_data/loaddata_pair.dat2
-rw-r--r--mysql-test/t/alias.test2
-rw-r--r--mysql-test/t/archive.test5
-rw-r--r--mysql-test/t/case.test11
-rw-r--r--mysql-test/t/ctype_ucs.test26
-rw-r--r--mysql-test/t/ctype_utf8.test46
-rw-r--r--mysql-test/t/disabled.def1
-rw-r--r--mysql-test/t/fulltext.test4
-rw-r--r--mysql-test/t/fulltext_order_by.test83
-rw-r--r--mysql-test/t/func_date_add.test2
-rw-r--r--mysql-test/t/func_des_encrypt.test9
-rw-r--r--mysql-test/t/func_encrypt.test16
-rw-r--r--mysql-test/t/func_encrypt_nossl.test37
-rw-r--r--mysql-test/t/func_str.test86
-rw-r--r--mysql-test/t/func_time.test2
-rw-r--r--mysql-test/t/grant.test76
-rw-r--r--mysql-test/t/group_by.test63
-rw-r--r--mysql-test/t/heap_hash.test2
-rw-r--r--mysql-test/t/index_merge.test3
-rw-r--r--mysql-test/t/index_merge_innodb.test11
-rw-r--r--mysql-test/t/information_schema.test20
-rw-r--r--mysql-test/t/innodb.test20
-rw-r--r--mysql-test/t/insert_select.test39
-rw-r--r--mysql-test/t/insert_update.test12
-rw-r--r--mysql-test/t/lowercase_table2.test3
-rw-r--r--mysql-test/t/mysqldump.test125
-rw-r--r--mysql-test/t/ndb_alter_table.test11
-rw-r--r--mysql-test/t/ndb_autodiscover.test22
-rw-r--r--mysql-test/t/ndb_insert.test15
-rw-r--r--mysql-test/t/ndb_subquery.test23
-rw-r--r--mysql-test/t/olap.test16
-rw-r--r--mysql-test/t/ps.test137
-rw-r--r--mysql-test/t/ps_1general.test6
-rw-r--r--mysql-test/t/ps_4heap.test2
-rw-r--r--mysql-test/t/ps_5merge.test4
-rw-r--r--mysql-test/t/query_cache.test44
-rw-r--r--mysql-test/t/range.test81
-rw-r--r--mysql-test/t/rpl_deadlock.test2
-rw-r--r--mysql-test/t/rpl_innodb.test46
-rw-r--r--mysql-test/t/rpl_multi_update3.test159
-rw-r--r--mysql-test/t/rpl_trunc_binlog.test35
-rw-r--r--mysql-test/t/rpl_until.test9
-rw-r--r--mysql-test/t/select.test273
-rw-r--r--mysql-test/t/show_check.test9
-rw-r--r--mysql-test/t/sp-error.test208
-rw-r--r--mysql-test/t/sp-goto.test238
-rw-r--r--mysql-test/t/sp-security.test67
-rw-r--r--mysql-test/t/sp-threads.test19
-rw-r--r--mysql-test/t/sp.test455
-rw-r--r--mysql-test/t/sql_mode.test51
-rw-r--r--mysql-test/t/strict.test10
-rw-r--r--mysql-test/t/subselect.test30
-rw-r--r--mysql-test/t/trigger.test101
-rw-r--r--mysql-test/t/type_bit.test53
-rw-r--r--mysql-test/t/type_blob.test9
-rw-r--r--mysql-test/t/type_decimal.test13
-rw-r--r--mysql-test/t/type_float.test7
-rw-r--r--mysql-test/t/type_newdecimal.test63
-rw-r--r--mysql-test/t/update.test4
-rw-r--r--mysql-test/t/variables.test6
-rw-r--r--mysql-test/t/view.test288
-rw-r--r--mysql-test/t/view_grant.test2
-rw-r--r--mysys/Makefile.am3
-rw-r--r--mysys/charset.c116
-rw-r--r--mysys/default.c148
-rw-r--r--mysys/default_modify.c158
-rw-r--r--mysys/hash.c3
-rw-r--r--mysys/my_access.c13
-rw-r--r--mysys/my_bitmap.c45
-rw-r--r--mysys/my_copy.c18
-rw-r--r--mysys/my_fopen.c84
-rw-r--r--mysys/my_os2cond.c2
-rw-r--r--mysys/tree.c3
-rw-r--r--ndb/include/kernel/AttributeList.hpp2
-rw-r--r--ndb/include/mgmcommon/ConfigRetriever.hpp1
-rw-r--r--ndb/include/ndb_version.h.in12
-rw-r--r--ndb/include/ndbapi/Ndb.hpp14
-rw-r--r--ndb/include/portlib/NdbTCP.h12
-rw-r--r--ndb/include/transporter/TransporterDefinitions.hpp3
-rw-r--r--ndb/include/transporter/TransporterRegistry.hpp2
-rw-r--r--ndb/include/util/SimpleProperties.hpp4
-rw-r--r--ndb/include/util/SocketServer.hpp8
-rw-r--r--ndb/include/util/ndb_opts.h2
-rw-r--r--ndb/include/util/version.h3
-rw-r--r--ndb/src/common/logger/LogHandler.cpp1
-rw-r--r--ndb/src/common/mgmcommon/ConfigRetriever.cpp23
-rw-r--r--ndb/src/common/portlib/NdbMutex.c16
-rw-r--r--ndb/src/common/portlib/NdbTCP.cpp9
-rw-r--r--ndb/src/common/portlib/NdbThread.c16
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.cpp2
-rw-r--r--ndb/src/common/transporter/Transporter.cpp15
-rw-r--r--ndb/src/common/transporter/Transporter.hpp1
-rw-r--r--ndb/src/common/transporter/TransporterRegistry.cpp18
-rw-r--r--ndb/src/common/util/Parser.cpp21
-rw-r--r--ndb/src/common/util/SimpleProperties.cpp34
-rw-r--r--ndb/src/common/util/SocketClient.cpp2
-rw-r--r--ndb/src/common/util/SocketServer.cpp4
-rw-r--r--ndb/src/common/util/version.c13
-rw-r--r--ndb/src/kernel/blocks/dbdih/DbdihMain.cpp1
-rw-r--r--ndb/src/kernel/blocks/qmgr/Qmgr.hpp4
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrMain.cpp51
-rw-r--r--ndb/src/mgmapi/mgmapi.cpp8
-rw-r--r--ndb/src/mgmapi/ndb_logevent.cpp20
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp30
-rw-r--r--ndb/src/mgmclient/main.cpp8
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp44
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.hpp13
-rw-r--r--ndb/src/mgmsrv/Services.cpp91
-rw-r--r--ndb/src/mgmsrv/main.cpp111
-rw-r--r--ndb/src/ndbapi/ClusterMgr.cpp18
-rw-r--r--ndb/src/ndbapi/DictCache.cpp108
-rw-r--r--ndb/src/ndbapi/DictCache.hpp2
-rw-r--r--ndb/src/ndbapi/Ndb.cpp116
-rw-r--r--ndb/src/ndbapi/NdbBlob.cpp417
-rw-r--r--ndb/src/ndbapi/NdbDictionary.cpp4
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp134
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.hpp78
-rw-r--r--ndb/src/ndbapi/NdbImpl.hpp18
-rw-r--r--ndb/src/ndbapi/NdbLinHash.hpp5
-rw-r--r--ndb/src/ndbapi/NdbScanOperation.cpp6
-rw-r--r--ndb/src/ndbapi/NdbTransaction.cpp8
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp8
-rw-r--r--ndb/src/ndbapi/Ndbinit.cpp2
-rw-r--r--ndb/src/ndbapi/Ndblist.cpp11
-rw-r--r--ndb/src/ndbapi/TransporterFacade.cpp25
-rw-r--r--ndb/test/ndbapi/testBlobs.cpp3
-rw-r--r--ndb/test/ndbapi/testDict.cpp22
-rw-r--r--ndb/test/ndbapi/testNdbApi.cpp101
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp130
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt4
-rw-r--r--ndb/tools/restore/restore_main.cpp3
-rw-r--r--netware/Makefile.am2
-rw-r--r--netware/my_print_defaults.def3
-rw-r--r--regex/Makefile.am2
-rw-r--r--scripts/make_binary_distribution.sh3
-rw-r--r--scripts/make_win_src_distribution.sh3
-rw-r--r--scripts/mysql_config.sh18
-rw-r--r--scripts/mysql_create_system_tables.sh14
-rw-r--r--scripts/mysql_fix_privilege_tables.sql50
-rw-r--r--sql-common/client.c44
-rw-r--r--sql/Makefile.am17
-rw-r--r--sql/des_key_file.cc18
-rw-r--r--sql/examples/ha_archive.cc262
-rw-r--r--sql/examples/ha_archive.h13
-rw-r--r--sql/field.cc57
-rw-r--r--sql/field.h11
-rw-r--r--sql/field_conv.cc33
-rw-r--r--sql/filesort.cc10
-rw-r--r--sql/ha_federated.cc45
-rw-r--r--sql/ha_heap.cc30
-rw-r--r--sql/ha_heap.h4
-rw-r--r--sql/ha_innodb.cc171
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_ndbcluster.cc511
-rw-r--r--sql/ha_ndbcluster.h8
-rw-r--r--sql/handler.cc108
-rw-r--r--sql/handler.h8
-rw-r--r--sql/item.cc715
-rw-r--r--sql/item.h272
-rw-r--r--sql/item_buff.cc6
-rw-r--r--sql/item_cmpfunc.cc100
-rw-r--r--sql/item_cmpfunc.h25
-rw-r--r--sql/item_create.cc12
-rw-r--r--sql/item_func.cc208
-rw-r--r--sql/item_func.h141
-rw-r--r--sql/item_row.cc4
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.cc89
-rw-r--r--sql/item_strfunc.h37
-rw-r--r--sql/item_subselect.cc61
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/item_sum.cc44
-rw-r--r--sql/item_sum.h117
-rw-r--r--sql/item_timefunc.cc8
-rw-r--r--sql/item_timefunc.h8
-rw-r--r--sql/item_uniq.h4
-rw-r--r--sql/lex.h5
-rw-r--r--sql/lock.cc13
-rw-r--r--sql/log.cc3
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/log_event.h3
-rw-r--r--sql/mysql_priv.h51
-rw-r--r--sql/mysqld.cc24
-rw-r--r--sql/net_serv.cc2
-rw-r--r--sql/opt_range.cc155
-rw-r--r--sql/protocol.cc69
-rw-r--r--sql/protocol.h2
-rw-r--r--sql/set_var.cc31
-rw-r--r--sql/set_var.h5
-rw-r--r--sql/share/errmsg.txt22
-rw-r--r--sql/slave.cc4
-rw-r--r--sql/sp.cc647
-rw-r--r--sql/sp.h25
-rw-r--r--sql/sp_head.cc246
-rw-r--r--sql/sp_head.h67
-rw-r--r--sql/sp_rcontext.cc9
-rw-r--r--sql/sp_rcontext.h12
-rw-r--r--sql/sql_acl.cc7
-rw-r--r--sql/sql_acl.h11
-rw-r--r--sql/sql_base.cc412
-rw-r--r--sql/sql_cache.cc14
-rw-r--r--sql/sql_class.cc197
-rw-r--r--sql/sql_class.h226
-rw-r--r--sql/sql_delete.cc9
-rw-r--r--sql/sql_derived.cc4
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_handler.cc11
-rw-r--r--sql/sql_help.cc26
-rw-r--r--sql/sql_insert.cc265
-rw-r--r--sql/sql_lex.cc144
-rw-r--r--sql/sql_lex.h98
-rw-r--r--sql/sql_load.cc20
-rw-r--r--sql/sql_map.cc2
-rw-r--r--sql/sql_olap.cc12
-rw-r--r--sql/sql_parse.cc155
-rw-r--r--sql/sql_prepare.cc216
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_select.cc396
-rw-r--r--sql/sql_select.h44
-rw-r--r--sql/sql_show.cc56
-rw-r--r--sql/sql_table.cc133
-rw-r--r--sql/sql_trigger.cc38
-rw-r--r--sql/sql_trigger.h27
-rw-r--r--sql/sql_udf.h4
-rw-r--r--sql/sql_union.cc64
-rw-r--r--sql/sql_update.cc41
-rw-r--r--sql/sql_view.cc169
-rw-r--r--sql/sql_view.h2
-rw-r--r--sql/sql_yacc.yy274
-rw-r--r--sql/table.cc493
-rw-r--r--sql/table.h56
-rw-r--r--sql/unireg.cc2
-rw-r--r--strings/Makefile.am2
-rw-r--r--strings/ctype-ucs2.c6
-rw-r--r--strings/ctype-utf8.c6
-rw-r--r--strings/ctype.c8
-rw-r--r--strings/decimal.c48
-rw-r--r--strings/xml.c67
-rw-r--r--support-files/mysql.spec.sh18
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/mysql_client_test.c596
-rw-r--r--tools/Makefile.am10
-rw-r--r--vio/Makefile.am3
-rw-r--r--vio/vio.c4
-rw-r--r--vio/viosocket.c5
-rw-r--r--vio/viossl.c2
-rw-r--r--zlib/inftrees.c2
483 files changed, 18792 insertions, 7931 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index a507d30e518..1603cfadbed 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -48,10 +48,9 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch
c_warnings="$global_warnings -Wunused"
cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
-base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-big-tables"
-max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-embedded-server --with-big-tables"
-max_no_es_configs="$max_leave_isam_configs --without-isam"
-max_configs="$max_no_es_configs --with-embedded-server"
+base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine"
+max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-openssl --with-embedded-server --with-big-tables"
+max_configs="$base_max_configs --with-embedded-server"
path=`dirname $0`
. "$path/check-cpu"
diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh
index 7daed25e56c..3adfafb0ce6 100755
--- a/BUILD/autorun.sh
+++ b/BUILD/autorun.sh
@@ -4,8 +4,14 @@
aclocal || (echo "Can't execute aclocal" && exit 1)
autoheader || (echo "Can't execute autoheader" && exit 1)
# --force means overwrite ltmain.sh script if it already exists
-libtoolize --automake --force \
- || (echo "Can't execute libtoolize" && exit 1)
+# Added glibtoolize reference to make native OSX autotools work
+if [ -f /usr/bin/glibtoolize ] ; then
+ glibtoolize --automake --force \
+ || (echo "Can't execute glibtoolize" && exit 1)
+else
+ libtoolize --automake --force \
+ || (echo "Can't execute libtoolize" && exit 1)
+fi
# --add-missing instructs automake to install missing auxiliary files
# and --force to overwrite them if they already exist
automake --add-missing --force \
diff --git a/BUILD/compile-pentium-debug-max-no-embedded b/BUILD/compile-pentium-debug-max-no-embedded
index 803a6a9d6d3..dfdf7d0a5e1 100755
--- a/BUILD/compile-pentium-debug-max-no-embedded
+++ b/BUILD/compile-pentium-debug-max-no-embedded
@@ -6,6 +6,6 @@ path=`dirname $0`
extra_flags="$pentium_cflags $debug_cflags $max_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
-extra_configs="$pentium_configs $debug_configs $max_no_es_configs"
+extra_configs="$pentium_configs $debug_configs $base_max_configs"
. "$path/FINISH.sh"
diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config
index 1ac24031dca..56ae08e5ffa 100644
--- a/BitKeeper/etc/config
+++ b/BitKeeper/etc/config
@@ -24,7 +24,7 @@ description: MySQL - fast and reliable SQL database
# repository is commercial it can be an internal email address or "none"
# to disable logging.
#
-logging: logging@openlogging.org
+logging: none
#
# If this field is set, all checkins will appear to be made by this user,
# in effect making this a single user package. Single user packages are
diff --git a/Docs/Makefile.am b/Docs/Makefile.am
index 6f8c51e79f0..b1f69381774 100644
--- a/Docs/Makefile.am
+++ b/Docs/Makefile.am
@@ -36,22 +36,22 @@ CLEAN_FILES: $(txt_files)
GT = $(srcdir)/Support/generate-text-files.pl
../INSTALL-SOURCE: mysql.info $(GT)
- perl -w $(GT) mysql.info "Installing" "Tutorial" > $@
+ perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@
../INSTALL-WIN-SOURCE: mysql.info $(GT)
- perl -w $(GT) mysql.info "Windows source build" "Post-installation" > $@
+ perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@
# We put the description for the binary installation here so that
# people who download source wont have to see it. It is moved up to
# the toplevel by the script that makes the binary tar files.
INSTALL-BINARY: mysql.info $(GT)
- perl -w $(GT) mysql.info "Installing binary" "Installing source" > $@
+ perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@
../EXCEPTIONS-CLIENT: mysql.info $(GT)
- perl -w $(GT) mysql.info "MySQL FLOSS License Exception" "Function Index" > $@
+ perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@
../support-files/MacOSX/ReadMe.txt: mysql.info $(GT)
- perl -w $(GT) mysql.info "Mac OS X installation" "NetWare installation" > $@
+ perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/Docs/README.1st b/Docs/README.1st
deleted file mode 100644
index 980c043224a..00000000000
--- a/Docs/README.1st
+++ /dev/null
@@ -1,76 +0,0 @@
-This ALPHA build of MySQL 4.1 for the Windows platform does not come
-with an installer. A full-featured installer is being developed for the
-4.1 series, and it is scheduled to be released with MySQL 4.1 BETA.
-
-** FRESH INSTALL **
-
-To install MySQL 4.1 as a 'fresh' install, unzip this archive to a directory
-of your choice (we suggest 'c:\', which will cause MySQL to be installed in
-a directory named 'mysql' in 'c:\'). You should then follow the directions
-in the user manual for starting/stopping MySQL:
-
-(Windows 9x/ME) http://www.mysql.com/doc/en/Win95_start.html
-(Windows NT/2000/XP) http://www.mysql.com/doc/en/NT_start.html
-
-** UPGRADE INSTALL **
-
-To install MySQL 4.1 as an upgrade to your current version of MySQL, you need
-to perform the following steps:
-
-* Back up your original installation (always a good idea!)
-
-* Unzip the 4.1 archive to a directory that is different than where your
- current MySQL installation is located. (Or, if you do unzip this
- archive into the same location as your existing installation, do NOT
- unpack the 'data' subdirectory. If you unpack the 'data' directory,
- your existing databases will be overwritten.)
-
-* Shut down all MySQL server processes/services.
-
-* Remove the Win32 MySQL service (if appropriate for your OS):
-
- c:\mysql\bin\mysqld-nt --remove
-
-* Exit 'WinMySQLAdmin' (if it is running).
-
-* If you unzipped this archive into a directory different than that
- of your existing MySQL installation, copy from the archive all its
- directories and their contents EXCEPT the 'data' directory into the
- existing installation.
-
-* Start the MySQL server with the '--skip-grant-tables' option. Assuming
- your MySQL installation is located at 'c:\mysql', the command looks like
- this:
-
- c:\mysql\bin\mysqld-opt --skip-grant-tables
-
- If your installation is located in some other directory, adjust the
- pathname in that command (and in the following commands).
-
-* Execute the 'mysql_fix_privilege_tables.sql' script that is located in
- the 'scripts' directory:
-
- c:\mysql\bin\mysql -f mysql < c:\mysql\scripts\mysql_fix_privilege_tables.sql
-
- This script performs any actions necessary to convert your grant tables
- to the current format. You may see some "duplicate column" warnings as
- it runs; these can be ignored.
-
-* Stop the server:
-
- c:\mysql\bin\mysqladmin -u root shutdown
-
-* Re-install the Win32 MySQL service (if required):
-
- c:\mysql\bin\mysqld-nt --install
-
-* Re-start the server or service using your normal startup procedure.
-
-** Further Questions **
-
-You can find further information about running MySQL on Windows in the
-manual that ships in the 'Doc' subdirectory, or online at the MySQL AB
-web site:
-
-http://www.mysql.com/doc/en/Windows.html
-
diff --git a/Docs/Support/generate-flag-images b/Docs/Support/generate-flag-images
deleted file mode 100755
index 21140388012..00000000000
--- a/Docs/Support/generate-flag-images
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-flags=`grep @image mirrors.texi | cut -d" " -f1 | cut -d/ -f2 | tr -d "}" | sort | uniq`
-
-set -x
-cd Flags
-
-for c in $flags
-do
- # For PNM, to be used later
- giftopnm ../Raw-Flags/$c.gif | pnmscale -xsize 30 > $c-tmp.pnm
- pnmpaste $c-tmp.pnm 1 1 ../Images/flag-background.pnm > $c.pnm
- rm -f $c-tmp.pnm
-
- # For GIF version
- ppmtogif $c.pnm > $c.gif
- # or cjpeg -optimize -quality 70 -outfile $c.jpg
-
- # For EPS version
- pnmtops -noturn $c.pnm > $c.eps
-
- # For PDF version
- ps2pdf $c.eps $c.pdf
-
- # For text version
- echo -n "" > $c.txt
-
- # PNM isn't really needed
- rm -f $c.pnm
-
-done
diff --git a/Docs/Support/generate-text-files.pl b/Docs/Support/generate-text-files.pl
index 6470baaa6e9..0829525f679 100755
--- a/Docs/Support/generate-text-files.pl
+++ b/Docs/Support/generate-text-files.pl
@@ -13,7 +13,7 @@ while (<IN>)
{
if ($in)
{
- if (/Node: $tnode,/)
+ if (/Node: $tnode,/ || /\[index/)
{
$in = 0;
}
diff --git a/Makefile.am b/Makefile.am
index b5ebe8eb8ae..6eb7421880e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,7 +23,7 @@ EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT
SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \
@readline_topdir@ sql-common \
@thread_dirs@ pstack \
- @sql_union_dirs@ scripts man tests \
+ @sql_union_dirs@ scripts @man_dirs@ tests \
netware @libmysqld_dirs@ \
@bench_dirs@ support-files @tools_dirs@
@@ -100,7 +100,8 @@ tags:
# Test installation
test:
- cd mysql-test; ./mysql-test-run && ./mysql-test-run --ps-protocol
+ cd mysql-test; \
+ ./mysql-test-run && ./mysql-test-run --ps-protocol
test-force:
cd mysql-test; \
diff --git a/VC++Files/libmysql/libmysql.dsp b/VC++Files/libmysql/libmysql.dsp
index bf6826ddc1f..356aac3563f 100644
--- a/VC++Files/libmysql/libmysql.dsp
+++ b/VC++Files/libmysql/libmysql.dsp
@@ -303,6 +303,10 @@ SOURCE=..\mysys\mulalloc.c
# End Source File
# Begin Source File
+SOURCE=..\mysys\my_access.c
+# End Source File
+# Begin Source File
+
SOURCE=..\mysys\my_alloc.c
# End Source File
# Begin Source File
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
index 4b49f5290c7..e8f24b300cb 100644
--- a/VC++Files/sql/mysqld.dsp
+++ b/VC++Files/sql/mysqld.dsp
@@ -84,7 +84,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\bdb.lib ..\lib_debug\innodb.lib ..\extra\yassl\Release\yassl.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld-debug.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\bdb.lib ..\lib_debug\innodb.lib ..\extra\yassl\Debug\yassl.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld-debug.exe" /pdbtype:sept
!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
diff --git a/VC++Files/tests/mysql_client_test.dsp b/VC++Files/tests/mysql_client_test.dsp
index 1d780ca5e0c..7d821b45f2b 100644
--- a/VC++Files/tests/mysql_client_test.dsp
+++ b/VC++Files/tests/mysql_client_test.dsp
@@ -51,8 +51,8 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib /nologo /out:"..\client_debug\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib /nologo /out:"..\client_debug\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console
!ELSEIF "$(CFG)" == "mysql_client_test - Win32 Release"
@@ -76,8 +76,8 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\client_release\mysql_client_test.exe" /incremental:no /libpath:"..\lib_release\" /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\client_release\mysql_client_test.exe" /incremental:no /libpath:"..\lib_release\" /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console
!ENDIF
diff --git a/client/Makefile.am b/client/Makefile.am
index a301d55efe4..d47e9f98f5e 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -22,8 +22,8 @@ else
yassl_dummy_link_fix=
endif
#AUTOMAKE_OPTIONS = nostdinc
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \
- $(openssl_includes) -I$(top_builddir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_srcdir)/regex $(openssl_includes)
LIBS = @CLIENT_LIBS@
LDADD= @CLIENT_EXTRA_LDFLAGS@ \
$(top_builddir)/libmysql/libmysqlclient.la
diff --git a/client/mysql.cc b/client/mysql.cc
index 96b523d8dc8..f98bf467588 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1011,7 +1011,8 @@ static int read_lines(bool execute_commands)
a nil, it still needs the space in the linebuffer for it. This is,
naturally, undocumented.
*/
- } while (linebuffer[0] <= linebuffer[1] + 1);
+ } while ((unsigned char)linebuffer[0] <=
+ (unsigned char)linebuffer[1] + 1);
line= buffer.c_ptr();
#endif /* __NETWARE__ */
#else
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 907b6233590..5705571777a 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -57,6 +57,7 @@
#define EX_CONSCHECK 3
#define EX_EOM 4
#define EX_EOF 5 /* ferror for output file was got */
+#define EX_ILLEGAL_TABLE 6
/* index into 'show fields from table' */
@@ -142,14 +143,6 @@ const char *compatible_mode_names[]=
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
"", compatible_mode_names, NULL};
-#define TABLE_RULE_HASH_SIZE 16
-
-typedef struct st_table_rule_ent
-{
- char* key; /* dbname.tablename */
- uint key_len;
-} TABLE_RULE_ENT;
-
HASH ignore_table;
static struct my_option my_long_options[] =
@@ -476,7 +469,10 @@ static void write_header(FILE *sql_file, char *db_name)
if (opt_xml)
{
fputs("<?xml version=\"1.0\"?>\n", sql_file);
- fputs("<mysqldump>\n", sql_file);
+ fputs("<mysqldump ", sql_file);
+ fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
+ sql_file);
+ fputs(">\n", sql_file);
check_io(sql_file);
}
else if (!opt_compact)
@@ -543,30 +539,29 @@ static void write_footer(FILE *sql_file)
}
} /* write_footer */
+static void free_table_ent(char *key)
-static void free_table_ent(TABLE_RULE_ENT* e)
{
- my_free((gptr) e, MYF(0));
+ my_free((gptr) key, MYF(0));
}
-static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
- my_bool not_used __attribute__((unused)))
+byte* get_table_key(const char *entry, uint *length,
+ my_bool not_used __attribute__((unused)))
{
- *len= e->key_len;
- return (byte*)e->key;
+ *length= strlen(entry);
+ return (byte*) entry;
}
void init_table_rule_hash(HASH* h)
{
- if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0,
- (hash_get_key) get_table_key,
- (hash_free_key) free_table_ent, 0))
+ if (hash_init(h, charset_info, 16, 0, 0,
+ (hash_get_key) get_table_key,
+ (hash_free_key) free_table_ent, 0))
exit(EX_EOM);
}
-
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
@@ -639,25 +634,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case (int) OPT_IGNORE_TABLE:
{
- uint len= (uint)strlen(argument);
- TABLE_RULE_ENT* e;
if (!strchr(argument, '.'))
{
fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
exit(1);
}
- /* len is always > 0 because we know the there exists a '.' */
- e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME));
- if (!e)
- exit(EX_EOM);
- e->key= (char*)e + sizeof(TABLE_RULE_ENT);
- e->key_len= len;
- memcpy(e->key, argument, len);
-
if (!hash_inited(&ignore_table))
init_table_rule_hash(&ignore_table);
- if(my_hash_insert(&ignore_table, (byte*)e))
+ if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0))))
exit(EX_EOM);
break;
}
@@ -828,7 +813,8 @@ static void DB_error(MYSQL *mysql, const char *when)
SYNOPSIS
mysql_query_with_error_report()
mysql_con connection to use
- res if non zero, result will be put there with mysql_store_result
+ res if non zero, result will be put there with
+ mysql_store_result()
query query to send to server
RETURN VALUES
@@ -981,14 +967,41 @@ static char *quote_name(const char *name, char *buff, my_bool force)
} /* quote_name */
+/*
+ Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
+
+ SYNOPSIS
+ quote_for_like()
+ name name of the table
+ buff quoted name of the table
+
+ DESCRIPTION
+ Quote \, _, ' and % characters
+
+ Note: Because MySQL uses the C escape syntax in strings
+ (for example, '\n' to represent newline), you must double
+ any '\' that you use in your LIKE strings. For example, to
+ search for '\n', specify it as '\\n'. To search for '\', specify
+ it as '\\\\' (the backslashes are stripped once by the parser
+ and another time when the pattern match is done, leaving a
+ single backslash to be matched).
+
+ Example: "t\1" => "t\\\\1"
+*/
static char *quote_for_like(const char *name, char *buff)
{
char *to= buff;
*to++= '\'';
while (*name)
{
- if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%')
+ if (*name == '\\')
+ {
+ *to++='\\';
+ *to++='\\';
+ *to++='\\';
+ }
+ else if (*name == '\'' || *name == '_' || *name == '%')
*to++= '\\';
*to++= *name++;
}
@@ -1074,6 +1087,40 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg,
/*
+ Print xml tag with for a field that is null
+
+ SYNOPSIS
+ print_xml_null_tag()
+ xml_file - output file
+ sbeg - line beginning
+ stag_atr - tag and attribute
+ sval - value of attribute
+ send - line ending
+
+ DESCRIPTION
+ Print tag with one attribute to the xml_file. Format is:
+ <stag_atr="sval" xsi:nil="true"/>
+ NOTE
+ sval MUST be a NULL terminated string.
+ sval string will be qouted before output.
+*/
+
+static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
+ const char* stag_atr, const char* sval,
+ const char* send)
+{
+ fputs(sbeg, xml_file);
+ fputs("<", xml_file);
+ fputs(stag_atr, xml_file);
+ fputs("\"", xml_file);
+ print_quoted_xml(xml_file, sval, strlen(sval));
+ fputs("\" xsi:nil=\"true\" />", xml_file);
+ fputs(send, xml_file);
+ check_io(xml_file);
+}
+
+
+/*
Print xml tag with many attributes.
SYNOPSIS
@@ -1139,6 +1186,7 @@ static uint get_table_structure(char *table, char *db)
FILE *sql_file = md_result_file;
int len;
DBUG_ENTER("get_table_structure");
+ DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
if (!insert_pat_inited)
{
@@ -1212,7 +1260,54 @@ static uint get_table_structure(char *table, char *db)
if (strcmp(field->name, "View") == 0)
{
if (verbose)
- fprintf(stderr, "-- It's a view, skipped\n");
+ fprintf(stderr, "-- It's a view, create dummy table for view\n");
+
+ mysql_free_result(tableRes);
+
+ /* Create a dummy table for the view. ie. a table which has the
+ same columns as the view should have. This table is dropped
+ just before the view is created. The table is used to handle the
+ case where a view references another view, which hasn't yet been
+ created(during the load of the dump). BUG#10927 */
+
+ /* Create temp table by selecting from the view */
+ my_snprintf(query_buff, sizeof(query_buff),
+ "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0",
+ result_table, result_table);
+ if (mysql_query_with_error_report(sock, 0, query_buff))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ /* Get CREATE statement for the temp table */
+ my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s",
+ result_table);
+ if (mysql_query_with_error_report(sock, 0, query_buff))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+ tableRes= mysql_store_result(sock);
+ row= mysql_fetch_row(tableRes);
+
+ if (opt_drop)
+ fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table);
+
+ /* Print CREATE statement but remove TEMPORARY */
+ fprintf(sql_file, "CREATE %s;\n", row[1]+17);
+ check_io(sql_file);
+
+ mysql_free_result(tableRes);
+
+ /* Drop the temp table */
+ my_snprintf(buff, sizeof(buff),
+ "DROP TEMPORARY TABLE %s", result_table);
+ if (mysql_query_with_error_report(sock, 0, buff))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
was_views= 1;
DBUG_RETURN(0);
}
@@ -1592,6 +1687,26 @@ static void dump_table(uint numFields, char *table)
const char *table_type;
int error= 0;
+ /* Check --no-data flag */
+ if (dFlag)
+ {
+ if (verbose)
+ fprintf(stderr,
+ "-- Skipping dump data for table '%s', --no-data was used\n",
+ table);
+ return;
+ }
+
+ /* Check that there are any fields in the table */
+ if (numFields == 0)
+ {
+ if (verbose)
+ fprintf(stderr,
+ "-- Skipping dump data for table '%s', it has no fields\n",
+ table);
+ return;
+ }
+
result_table= quote_name(table,table_buff, 1);
opt_quoted_table= quote_name(table, table_buff2, 0);
@@ -1912,7 +2027,14 @@ static void dump_table(uint numFields, char *table)
}
}
else
- fputs("NULL", md_result_file);
+ {
+ /* The field value is NULL */
+ if (!opt_xml)
+ fputs("NULL", md_result_file);
+ else
+ print_xml_null_tag(md_result_file, "\t\t", "field name=",
+ field->name, "\n");
+ }
check_io(md_result_file);
}
}
@@ -2201,8 +2323,7 @@ static int dump_all_tables_in_db(char *database)
if (include_table(hash_key, end - hash_key))
{
numrows = get_table_structure(table, database);
- if (!dFlag && numrows > 0)
- dump_table(numrows,table);
+ dump_table(numrows,table);
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
order_by= 0;
}
@@ -2327,27 +2448,61 @@ static int get_actual_table_name(const char *old_table_name,
static int dump_selected_tables(char *db, char **table_names, int tables)
{
- uint numrows;
- int i;
+ uint numrows, i;
char table_buff[NAME_LEN*+3];
+ char new_table_name[NAME_LEN];
+ DYNAMIC_STRING lock_tables_query;
+ HASH dump_tables;
+ char *table_name;
+ DBUG_ENTER("dump_selected_tables");
if (init_dumping(db))
return 1;
- if (lock_tables)
+
+ /* Init hash table for storing the actual name of tables to dump */
+ if (hash_init(&dump_tables, charset_info, 16, 0, 0,
+ (hash_get_key) get_table_key, (hash_free_key) free_table_ent,
+ 0))
+ exit(EX_EOM);
+
+ init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
+ for (; tables > 0 ; tables-- , table_names++)
{
- DYNAMIC_STRING query;
+ /* the table name passed on commandline may be wrong case */
+ if (!get_actual_table_name(*table_names,
+ new_table_name, sizeof(new_table_name)))
+ {
+ /* Add found table name to lock_tables_query */
+ if (lock_tables)
+ {
+ dynstr_append(&lock_tables_query,
+ quote_name(new_table_name, table_buff, 1));
+ dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
+ }
- init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
- for (i=0 ; i < tables ; i++)
+ /* Add found table name to dump_tables list */
+ if (my_hash_insert(&dump_tables,
+ (byte*)my_strdup(new_table_name, MYF(0))))
+ exit(EX_EOM);
+
+ }
+ else
{
- dynstr_append(&query, quote_name(table_names[i], table_buff, 1));
- dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0),
+ *table_names);
+ safe_exit(EX_ILLEGAL_TABLE);
+ /* We shall countinue here, if --force was given */
}
- if (mysql_real_query(sock, query.str, query.length-1))
+ }
+
+ if (lock_tables)
+ {
+ if (mysql_real_query(sock, lock_tables_query.str,
+ lock_tables_query.length-1))
DB_error(sock, "when doing LOCK TABLES");
/* We shall countinue here, if --force was given */
- dynstr_free(&query);
}
+ dynstr_free(&lock_tables_query);
if (flush_logs)
{
if (mysql_refresh(sock, REFRESH_LOG))
@@ -2356,25 +2511,28 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
}
if (opt_xml)
print_xml_tag1(md_result_file, "", "database name=", db, "\n");
- for (i=0 ; i < tables ; i++)
- {
- char new_table_name[NAME_LEN];
- /* the table name passed on commandline may be wrong case */
- if (!get_actual_table_name( table_names[i], new_table_name,
- sizeof(new_table_name)))
- {
- numrows= get_table_structure(new_table_name, db);
- dump_table(numrows, new_table_name);
- }
- my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
- order_by= 0;
+ /* Dump each selected table */
+ for (i= 0; i < dump_tables.records; i++)
+ {
+ table_name= hash_element(&dump_tables, i);
+ DBUG_PRINT("info",("Dumping table %s", table_name));
+ numrows= get_table_structure(table_name, db);
+ dump_table(numrows, table_name);
}
+
+ /* Dump each selected view */
if (was_views)
{
- for (i=0 ; i < tables ; i++)
- get_view_structure(table_names[i], db);
+ for(i=0; i < dump_tables.records; i++)
+ {
+ table_name= hash_element(&dump_tables, i);
+ get_view_structure(table_name, db);
+ }
}
+ hash_free(&dump_tables);
+ my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
+ order_by= 0;
if (opt_xml)
{
fputs("</database>\n", md_result_file);
@@ -2382,7 +2540,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
}
if (lock_tables)
mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
- return 0;
+ DBUG_RETURN(0);
} /* dump_selected_tables */
@@ -2403,6 +2561,7 @@ static int do_show_master_status(MYSQL *mysql_con)
row = mysql_fetch_row(master);
if (row && row[0] && row[1])
{
+ /* SHOW MASTER STATUS reports file and position */
if (opt_comments)
fprintf(md_result_file,
"\n--\n-- Position to start replication or point-in-time "
@@ -2412,6 +2571,14 @@ static int do_show_master_status(MYSQL *mysql_con)
comment_prefix, row[0], row[1]);
check_io(md_result_file);
}
+ else if (!ignore_errors)
+ {
+ /* SHOW MASTER STATUS reports nothing and --force is not enabled */
+ my_printf_error(0, "Error: Binlogging on server not active",
+ MYF(0), mysql_error(mysql_con));
+ mysql_free_result(master);
+ return 1;
+ }
mysql_free_result(master);
}
return 0;
@@ -2752,6 +2919,7 @@ static my_bool get_view_structure(char *table, char* db)
}
if (opt_drop)
{
+ fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
check_io(sql_file);
}
@@ -2775,8 +2943,9 @@ int main(int argc, char **argv)
{
compatible_mode_normal_str[0]= 0;
default_charset= (char *)mysql_universal_client_charset;
+ bzero((char*) &ignore_table, sizeof(ignore_table));
- MY_INIT(argv[0]);
+ MY_INIT("mysqldump");
if (get_options(&argc, &argv))
{
my_end(0);
@@ -2833,6 +3002,8 @@ err:
if (md_result_file != stdout)
my_fclose(md_result_file, MYF(0));
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
+ if (hash_inited(&ignore_table))
+ hash_free(&ignore_table);
if (extended_insert)
dynstr_free(&extended_row);
if (insert_pat_inited)
diff --git a/client/mysqltest.c b/client/mysqltest.c
index ad1bc8f7269..67fa931a3f3 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -60,6 +60,12 @@
#include <sys/stat.h>
#include <violite.h>
#include <regex.h> /* Our own version of lib */
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
#define MAX_QUERY 131072
#define MAX_VAR_NAME 256
#define MAX_COLUMNS 256
@@ -986,9 +992,39 @@ static void do_exec(struct st_query* q)
replace_dynstr_append(ds, buf);
}
error= pclose(res_file);
-
if (error != 0)
- die("command \"%s\" failed", cmd);
+ {
+ uint status= WEXITSTATUS(error), i;
+ my_bool ok= 0;
+
+ if (q->abort_on_error)
+ die("At line %u: command \"%s\" failed", start_lineno, cmd);
+
+ DBUG_PRINT("info",
+ ("error: %d, status: %d", error, status));
+ for (i=0 ; (uint) i < q->expected_errors ; i++)
+ {
+ DBUG_PRINT("info",
+ ("error: %d, status: %d", error, status));
+ DBUG_PRINT("info", ("expected error: %d",
+ q->expected_errno[i].code.errnum));
+ if ((q->expected_errno[i].type == ERR_ERRNO) &&
+ (q->expected_errno[i].code.errnum == status))
+ ok= 1;
+ verbose_msg("At line %u: command \"%s\" failed with expected error: %d",
+ start_lineno, cmd, status);
+ }
+ if (!ok)
+ die("At line: %u: command \"%s\" failed with wrong error: %d",
+ start_lineno, cmd, status);
+ }
+ else if (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0)
+ {
+ /* Error code we wanted was != 0, i.e. not an expected success */
+ die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...",
+ start_lineno, cmd, q->expected_errno[0].code.errnum);
+ }
if (!disable_result_log)
{
diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am
index 03f3eb65fbc..af1bf8b2c97 100644
--- a/cmd-line-utils/libedit/Makefile.am
+++ b/cmd-line-utils/libedit/Makefile.am
@@ -5,7 +5,8 @@
ASRC=vi.c emacs.c common.c
AHDR=vi.h emacs.h common.h
-INCLUDES = -I$(top_srcdir)/include -I$(srcdir)/../.. -I..
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(srcdir)/../.. -I..
noinst_LIBRARIES = libedit.a
diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c
index 21fc8bc2c1d..4cb6e00d26e 100644
--- a/cmd-line-utils/libedit/chared.c
+++ b/cmd-line-utils/libedit/chared.c
@@ -51,13 +51,13 @@ cv_undo(EditLine *el)
{
c_undo_t *vu = &el->el_chared.c_undo;
c_redo_t *r = &el->el_chared.c_redo;
- uint size;
+ int size;
/* Save entire line for undo */
size = el->el_line.lastchar - el->el_line.buffer;
vu->len = size;
vu->cursor = el->el_line.cursor - el->el_line.buffer;
- memcpy(vu->buf, el->el_line.buffer, size);
+ memcpy(vu->buf, el->el_line.buffer, (size_t)size);
/* save command info for redo */
r->count = el->el_state.doingarg ? el->el_state.argument : 0;
diff --git a/cmd-line-utils/readline/Makefile.am b/cmd-line-utils/readline/Makefile.am
index 87880517166..14d25ff62c0 100644
--- a/cmd-line-utils/readline/Makefile.am
+++ b/cmd-line-utils/readline/Makefile.am
@@ -3,7 +3,8 @@
# Copyright (C) 1994,1996,1997 Free Software Foundation, Inc.
# Last -I$(top_srcdir) needed for RedHat!
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_srcdir)
noinst_LIBRARIES = libreadline.a
diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4
index e2564c2b80a..6f93f38f119 100644
--- a/config/ac-macros/misc.m4
+++ b/config/ac-macros/misc.m4
@@ -710,3 +710,59 @@ fi
])
+AC_DEFUN([MYSQL_CHECK_CXX_VERSION], [
+case $SYSTEM_TYPE in
+ *netware*)
+ CXX_VERSION=`$CXX -version | grep -i version`
+ ;;
+ *)
+ CXX_VERSION=`$CXX --version | sed 1q`
+ if test $? -ne "0" -o -z "$CXX_VERSION"
+ then
+ CXX_VERSION=`$CXX -V 2>&1|sed 1q` # trying harder for Sun and SGI
+ fi
+ if test $? -ne "0" -o -z "$CXX_VERSION"
+ then
+ CXX_VERSION=`$CXX -v 2>&1|sed 1q` # even harder for Alpha
+ fi
+ if test $? -ne "0" -o -z "$CXX_VERSION"
+ then
+ CXX_VERSION=""
+ fi
+esac
+if test "$CXX_VERSION"
+then
+ AC_MSG_CHECKING("C++ compiler version");
+ AC_MSG_RESULT("$CXX $CXX_VERSION")
+fi
+AC_SUBST(CXX_VERSION)
+])
+
+AC_DEFUN([MYSQL_PROG_AR], [
+AC_REQUIRE([MYSQL_CHECK_CXX_VERSION])
+case $CXX_VERSION in
+ MIPSpro*)
+ AR=$CXX
+ ARFLAGS="-ar -o"
+ ;;
+ *Forte*)
+ AR=$CXX
+ ARFLAGS="-xar -o"
+ ;;
+ *)
+ if test -z "$AR"
+ then
+ AC_CHECK_PROG([AR], [ar], [ar])
+ fi
+ if test -z "$AR"
+ then
+ AC_MSG_ERROR([You need ar to build the library])
+ fi
+ if test -z "$ARFLAGS"
+ then
+ ARFLAGS="cru"
+ fi
+esac
+AC_SUBST(AR)
+AC_SUBST(ARFLAGS)
+])
diff --git a/configure.in b/configure.in
index 89c1b390610..8ea135c3613 100644
--- a/configure.in
+++ b/configure.in
@@ -1,12 +1,12 @@
dnl -*- ksh -*-
dnl Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.50)dnl Minimum Autoconf version required.
+AC_PREREQ(2.58)dnl Minimum Autoconf version required.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# Don't forget to also update the NDB lines below.
-AM_INIT_AUTOMAKE(mysql, 5.0.8-beta)
+AM_INIT_AUTOMAKE(mysql, 5.0.10-beta)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -17,7 +17,7 @@ SHARED_LIB_VERSION=14:0:0
# ndb version
NDB_VERSION_MAJOR=5
NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=8
+NDB_VERSION_BUILD=10
NDB_VERSION_STATUS="beta"
# Set all version vars based on $VERSION. How do we do this more elegant ?
@@ -196,23 +196,8 @@ then
else
CC_VERSION=""
fi
-case $SYSTEM_TYPE in
- *netware*)
-CXX_VERSION=`$CXX -version | grep -i version`
- ;;
- *)
-CXX_VERSION=`$CXX --version | sed 1q`
- ;;
-esac
-if test $? -eq "0"
-then
- AC_MSG_CHECKING("C++ compiler version");
- AC_MSG_RESULT("$CXX $CXX_VERSION")
-else
-CXX_VERSION=""
-fi
-AC_SUBST(CXX_VERSION)
AC_SUBST(CC_VERSION)
+MYSQL_CHECK_CXX_VERSION
# Fix for sgi gcc / sgiCC which tries to emulate gcc
if test "$CC" = "sgicc"
@@ -358,7 +343,7 @@ AC_SUBST(CXXFLAGS)
AC_SUBST(LD)
AC_SUBST(INSTALL_SCRIPT)
-export CC CXX CFLAGS LD LDFLAGS AR
+export CC CXX CFLAGS LD LDFLAGS AR ARFLAGS
if test "$GCC" = "yes"
then
@@ -366,8 +351,12 @@ then
# Disable exceptions as they seams to create problems with gcc and threads.
# mysqld doesn't use run-time-type-checking, so we disable it.
CXXFLAGS="$CXXFLAGS -fno-implicit-templates -fno-exceptions -fno-rtti"
+ AC_DEFINE([HAVE_EXPLICIT_TEMPLATE_INSTANTIATION],
+ [1], [Defined by configure. Use explicit template instantiation.])
fi
+MYSQL_PROG_AR
+
# Avoid bug in fcntl on some versions of linux
AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os")
# Any variation of Linux
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
index 0810b13cceb..38705e63847 100644
--- a/dbug/Makefile.am
+++ b/dbug/Makefile.am
@@ -15,7 +15,7 @@
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
LDADD = libdbug.a ../mysys/libmysys.a ../strings/libmystrings.a
pkglib_LIBRARIES = libdbug.a
noinst_HEADERS = dbug_long.h
diff --git a/extra/Makefile.am b/extra/Makefile.am
index 3aa4c531709..cb06e7495f9 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -14,9 +14,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-INCLUDES = -I$(top_srcdir)/include \
- @ndbcluster_includes@ -I$(top_srcdir)/sql \
- -I$(top_builddir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ @ndbcluster_includes@ -I$(top_srcdir)/sql
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \
diff --git a/extra/yassl/include/yassl_types.hpp b/extra/yassl/include/yassl_types.hpp
index 01b82d95039..ec9e6fb7ceb 100644
--- a/extra/yassl/include/yassl_types.hpp
+++ b/extra/yassl/include/yassl_types.hpp
@@ -445,7 +445,7 @@ const opaque master_label[MASTER_LABEL_SZ + 1] = "master secret";
const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion";
-} // namespace
+} // naemspace
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
/*
@@ -456,4 +456,5 @@ const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion";
using yaSSL::byte;
#endif
+
#endif // yaSSL_TYPES_HPP
diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am
index 1f5f1ee7a4e..4ebb9a2d862 100644
--- a/extra/yassl/src/Makefile.am
+++ b/extra/yassl/src/Makefile.am
@@ -5,3 +5,4 @@ libyassl_a_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
+AM_CXXFLAGS = -DYASSL_PURE_C
diff --git a/extra/yassl/src/buffer.cpp b/extra/yassl/src/buffer.cpp
index 1da0827ac4e..56d355bea80 100644
--- a/extra/yassl/src/buffer.cpp
+++ b/extra/yassl/src/buffer.cpp
@@ -25,6 +25,7 @@
*/
#include <string.h> // memcpy
+#include "runtime.hpp"
#include "buffer.hpp"
#include "yassl_types.hpp"
diff --git a/extra/yassl/src/cert_wrapper.cpp b/extra/yassl/src/cert_wrapper.cpp
index 7a8c7dfe253..a775c366a92 100644
--- a/extra/yassl/src/cert_wrapper.cpp
+++ b/extra/yassl/src/cert_wrapper.cpp
@@ -24,6 +24,7 @@
*
*/
+#include "runtime.hpp"
#include "cert_wrapper.hpp"
#include "yassl_int.hpp"
diff --git a/extra/yassl/src/crypto_wrapper.cpp b/extra/yassl/src/crypto_wrapper.cpp
index ff1b4b630c2..80cadd3d722 100644
--- a/extra/yassl/src/crypto_wrapper.cpp
+++ b/extra/yassl/src/crypto_wrapper.cpp
@@ -971,7 +971,7 @@ x509* PemToDer(const char* fname, CertType type)
} // namespace
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace yaSSL {
template void ysDelete<DiffieHellman::DHImpl>(DiffieHellman::DHImpl*);
template void ysDelete<Integer::IntegerImpl>(Integer::IntegerImpl*);
@@ -989,6 +989,6 @@ template void ysDelete<RMD::RMDImpl>(RMD::RMDImpl*);
template void ysDelete<SHA::SHAImpl>(SHA::SHAImpl*);
template void ysDelete<MD5::MD5Impl>(MD5::MD5Impl*);
}
-#endif // __GNUC__
+#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
#endif // !USE_CRYPTOPP_LIB
diff --git a/extra/yassl/src/lock.cpp b/extra/yassl/src/lock.cpp
index 8a0b66ead42..4827d396e81 100644
--- a/extra/yassl/src/lock.cpp
+++ b/extra/yassl/src/lock.cpp
@@ -22,6 +22,7 @@
/* Locking functions
*/
+#include "runtime.hpp"
#include "lock.hpp"
diff --git a/extra/yassl/src/log.cpp b/extra/yassl/src/log.cpp
index 38633cd1210..8ab351ee2b1 100644
--- a/extra/yassl/src/log.cpp
+++ b/extra/yassl/src/log.cpp
@@ -22,6 +22,8 @@
/* Debug logging functions
*/
+
+#include "runtime.hpp"
#include "log.hpp"
#ifdef YASSL_LOG
diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp
index 00f9c8d170c..2252dfafdc5 100644
--- a/extra/yassl/src/socket_wrapper.cpp
+++ b/extra/yassl/src/socket_wrapper.cpp
@@ -26,6 +26,7 @@
*/
+#include "runtime.hpp"
#include "socket_wrapper.hpp"
#ifndef _WIN32
diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp
index 4ad1ec29249..5ee57e76aed 100644
--- a/extra/yassl/src/template_instnt.cpp
+++ b/extra/yassl/src/template_instnt.cpp
@@ -1,3 +1,29 @@
+/* template_instnt.cpp
+ *
+ * Copyright (C) 2003 Sawtooth Consulting Ltd.
+ *
+ * This file is part of yaSSL.
+ *
+ * yaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * yaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* Explicit template instantiation requests
+ */
+
+
#include "runtime.hpp"
#include "handshake.hpp"
#include "yassl_int.hpp"
@@ -8,36 +34,36 @@
#include "ripemd.hpp"
#include "openssl/ssl.h"
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
#if !defined(USE_CRYPTOPP_LIB)
namespace TaoCrypt {
template class HMAC<MD5>;
template class HMAC<SHA>;
template class HMAC<RIPEMD160>;
}
-#endif
+#endif // USE_CRYPTOPP_LIB
namespace mySTL {
-template class mySTL::list<unsigned char*>;
-template yaSSL::del_ptr_zero mySTL::for_each(mySTL::list<unsigned char*>::iterator, mySTL::list<unsigned char*>::iterator, yaSSL::del_ptr_zero);
-template mySTL::pair<int, yaSSL::Message* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
-template mySTL::pair<int, yaSSL::HandShakeBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
-template void mySTL::destroy<mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
-template void mySTL::destroy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
-template mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
-template void mySTL::destroy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
-template mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
-template class mySTL::list<TaoCrypt::Signer*>;
-template class mySTL::list<yaSSL::SSL_SESSION*>;
-template class mySTL::list<yaSSL::input_buffer*>;
-template class mySTL::list<yaSSL::output_buffer*>;
-template class mySTL::list<yaSSL::x509*>;
-template void mySTL::destroy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
-template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<TaoCrypt::Signer*>::iterator, mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero);
-template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero);
-template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero);
-template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero);
-template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::x509*>::iterator, mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero);
+template class list<unsigned char*>;
+template yaSSL::del_ptr_zero for_each(mySTL::list<unsigned char*>::iterator, mySTL::list<unsigned char*>::iterator, yaSSL::del_ptr_zero);
+template pair<int, yaSSL::Message* (*)()>* uninit_copy<mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
+template pair<int, yaSSL::HandShakeBase* (*)()>* uninit_copy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
+template void destroy<mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
+template void destroy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
+template pair<int, yaSSL::ServerKeyBase* (*)()>* uninit_copy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
+template void destroy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
+template pair<int, yaSSL::ClientKeyBase* (*)()>* uninit_copy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
+template class list<TaoCrypt::Signer*>;
+template class list<yaSSL::SSL_SESSION*>;
+template class list<yaSSL::input_buffer*>;
+template class list<yaSSL::output_buffer*>;
+template class list<yaSSL::x509*>;
+template void destroy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
+template yaSSL::del_ptr_zero for_each<mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<TaoCrypt::Signer*>::iterator, mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero for_each<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero for_each<mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::x509*>::iterator, mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero);
}
namespace yaSSL {
@@ -64,4 +90,6 @@ template void ysDelete<Message>(Message*);
template void ysArrayDelete<unsigned char>(unsigned char*);
template void ysArrayDelete<char>(char*);
}
-#endif
+
+#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+
diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp
index cfa1319ae80..4fe0d3aa4f9 100644
--- a/extra/yassl/src/timer.cpp
+++ b/extra/yassl/src/timer.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "runtime.hpp"
#include "timer.hpp"
namespace yaSSL {
diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp
index 6ae5a9f6663..c53aef2068d 100644
--- a/extra/yassl/src/yassl_error.cpp
+++ b/extra/yassl/src/yassl_error.cpp
@@ -23,6 +23,7 @@
/* yaSSL error implements and an exception class
*/
+#include "runtime.hpp"
#include "yassl_error.hpp"
namespace yaSSL {
diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp
index 06be7a15503..740618ce701 100644
--- a/extra/yassl/src/yassl_int.cpp
+++ b/extra/yassl/src/yassl_int.cpp
@@ -24,6 +24,7 @@
* draft along with type conversion functions.
*/
+#include "runtime.hpp"
#include "yassl_int.hpp"
#include "handshake.hpp"
#include "timer.hpp"
@@ -32,28 +33,36 @@
void* operator new(size_t sz, yaSSL::new_t)
{
+#ifdef YASSL_PURE_C
void* ptr = malloc(sz ? sz : 1);
if (!ptr) abort();
return ptr;
+#else
+ return ::operator new(sz);
+#endif
}
-void* operator new[](size_t sz, yaSSL::new_t)
-{
- void* ptr = malloc(sz ? sz : 1);
- if (!ptr) abort();
-
- return ptr;
-}
void operator delete(void* ptr, yaSSL::new_t)
{
+#ifdef YASSL_PURE_C
if (ptr) free(ptr);
+#else
+ ::operator delete(ptr);
+#endif
+}
+
+
+void* operator new[](size_t sz, yaSSL::new_t nt)
+{
+ return ::operator new(sz, nt);
}
-void operator delete[](void* ptr, yaSSL::new_t)
+
+void operator delete[](void* ptr, yaSSL::new_t nt)
{
- if (ptr) free(ptr);
+ ::operator delete(ptr, nt);
}
@@ -922,7 +931,7 @@ void SSL::setKeys()
// local functors
-namespace yassl_int_cpp_local1 {
+namespace yassl_int_cpp_local1 { // for explicit templates
struct SumData {
uint total_;
@@ -1384,7 +1393,8 @@ Sessions::~Sessions()
}
-namespace yassl_int_cpp_local2 { // locals
+// locals
+namespace yassl_int_cpp_local2 { // for explicit templates
typedef mySTL::list<SSL_SESSION*>::iterator iterator;
@@ -1973,12 +1983,15 @@ X509_NAME* X509::GetSubject()
return &subject_;
}
+
+
} // namespace
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace mySTL {
-template yaSSL::yassl_int_cpp_local1::SumData mySTL::for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData);
-template yaSSL::yassl_int_cpp_local1::SumBuffer mySTL::for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer);
-template mySTL::list<yaSSL::SSL_SESSION*>::iterator mySTL::find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match);
+template yaSSL::yassl_int_cpp_local1::SumData for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData);
+template yaSSL::yassl_int_cpp_local1::SumBuffer for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer);
+template mySTL::list<yaSSL::SSL_SESSION*>::iterator find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match);
}
#endif
+
diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp
index 01106b6f960..f506040f0d8 100644
--- a/extra/yassl/taocrypt/include/runtime.hpp
+++ b/extra/yassl/taocrypt/include/runtime.hpp
@@ -25,7 +25,7 @@
-#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__)
+#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) && !defined(__ICC)
#define yaSSL_NEW_HPP
@@ -34,6 +34,8 @@
extern "C" {
#include <assert.h>
+/* Disallow inline __cxa_pure_virtual() */
+static int __cxa_pure_virtual() __attribute__((noinline, used));
static int __cxa_pure_virtual()
{
// oops, pure virtual called!
diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp
index d497d45e1da..92164eaaab4 100644
--- a/extra/yassl/taocrypt/include/types.hpp
+++ b/extra/yassl/taocrypt/include/types.hpp
@@ -25,12 +25,14 @@
#ifndef TAO_CRYPT_TYPES_HPP
#define TAO_CRYPT_TYPES_HPP
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
namespace TaoCrypt {
-// define this if running on a big-endian CPU
-#if !defined(LITTLE_ENDIAN_ORDER) && (defined(__BIG_ENDIAN__) || \
- defined(__sparc) || defined(__sparc__) || defined(__hppa__) || \
- defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__)))
+
+#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__))
#define BIG_ENDIAN_ORDER
#endif
@@ -43,34 +45,28 @@ typedef unsigned char byte;
typedef unsigned short word16;
typedef unsigned int word32;
-#if defined(__GNUC__) || defined(__MWERKS__) || defined(_LONGLONG_TYPE)
- #define WORD64_AVAILABLE
- #define WORD64_IS_DISTINCT_TYPE
- typedef unsigned long long word64;
- #define W64LIT(x) x##LL
-#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
#define WORD64_AVAILABLE
#define WORD64_IS_DISTINCT_TYPE
typedef unsigned __int64 word64;
- #define W64LIT(x) x##ui64
-#elif defined(__DECCXX)
+#elif SIZEOF_LONG == 8
#define WORD64_AVAILABLE
typedef unsigned long word64;
+#elif SIZEOF_LONG_LONG == 8
+ #define WORD64_AVAILABLE
+ #define WORD64_IS_DISTINCT_TYPE
+ typedef unsigned long long word64;
#endif
-// define largest word type
-#ifdef WORD64_AVAILABLE
- typedef word64 lword;
-#else
- typedef word32 lword;
-#endif
+// compilers we've found 64-bit multiply insructions for
+#if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX)
+ #define HAVE_64_MULTIPLY
+#endif
-// TODO: FIXME, add asm multiply for x86_64 on Solaris and remove !__sun
-#if defined(__alpha__) || (defined(__ia64__) && !defined(__INTEL_COMPILER)) || \
- defined(_ARCH_PPC64) || defined(__mips64) || \
- (defined(__x86_64__) && !defined(__sun))
+#if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \
+ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__))
// These platforms have 64-bit CPU registers. Unfortunately most C++ compilers
// don't allow any way to access the 64-bit by 64-bit multiply instruction
// without using assembly, so in order to use word64 as word, the assembly
@@ -80,7 +76,7 @@ typedef unsigned int word32;
#else
#define TAOCRYPT_NATIVE_DWORD_AVAILABLE
#ifdef WORD64_AVAILABLE
- #define TAOCRYPT_SLOW_WORD64
+ #define TAOCRYPT_SLOW_WORD64
typedef word16 hword;
typedef word32 word;
typedef word64 dword;
diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am
index 4005be94fb2..5bf45074a98 100644
--- a/extra/yassl/taocrypt/src/Makefile.am
+++ b/extra/yassl/taocrypt/src/Makefile.am
@@ -6,3 +6,4 @@ libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \
md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \
template_instnt.cpp
EXTRA_DIST = ../include/*.hpp
+AM_CXXFLAGS = -DYASSL_PURE_C
diff --git a/extra/yassl/taocrypt/src/aestables.cpp b/extra/yassl/taocrypt/src/aestables.cpp
index 5a125dfd44d..7ba25bc9ffb 100644
--- a/extra/yassl/taocrypt/src/aestables.cpp
+++ b/extra/yassl/taocrypt/src/aestables.cpp
@@ -21,6 +21,7 @@
/* based on Wei Dai's aestables.cpp from CryptoPP */
+#include "runtime.hpp"
#include "aes.hpp"
diff --git a/extra/yassl/taocrypt/src/algebra.cpp b/extra/yassl/taocrypt/src/algebra.cpp
index 7608e78b0ed..45bbcfa662a 100644
--- a/extra/yassl/taocrypt/src/algebra.cpp
+++ b/extra/yassl/taocrypt/src/algebra.cpp
@@ -319,9 +319,11 @@ void AbstractRing::SimultaneousExponentiate(Integer *results,
} // namespace
-#ifdef __GNUC__
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace mySTL {
template TaoCrypt::WindowSlider* uninit_copy<TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*);
template void destroy<TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*);
}
#endif
+
diff --git a/extra/yassl/taocrypt/src/arc4.cpp b/extra/yassl/taocrypt/src/arc4.cpp
index bbd77cd822c..1e521b48f0c 100644
--- a/extra/yassl/taocrypt/src/arc4.cpp
+++ b/extra/yassl/taocrypt/src/arc4.cpp
@@ -21,6 +21,7 @@
/* based on Wei Dai's arc4.cpp from CryptoPP */
+#include "runtime.hpp"
#include "arc4.hpp"
diff --git a/extra/yassl/taocrypt/src/coding.cpp b/extra/yassl/taocrypt/src/coding.cpp
index 6514ed4d46d..944a47c288e 100644
--- a/extra/yassl/taocrypt/src/coding.cpp
+++ b/extra/yassl/taocrypt/src/coding.cpp
@@ -22,6 +22,7 @@
/* coding.cpp implements hex and base64 encoding/decoing
*/
+#include "runtime.hpp"
#include "coding.hpp"
#include "file.hpp"
diff --git a/extra/yassl/taocrypt/src/dh.cpp b/extra/yassl/taocrypt/src/dh.cpp
index d5f93f6c0f6..ea1b5846f7d 100644
--- a/extra/yassl/taocrypt/src/dh.cpp
+++ b/extra/yassl/taocrypt/src/dh.cpp
@@ -23,6 +23,7 @@
/* dh.cpp implements Diffie-Hellman support
*/
+#include "runtime.hpp"
#include "dh.hpp"
#include "asn.hpp"
diff --git a/extra/yassl/taocrypt/src/dsa.cpp b/extra/yassl/taocrypt/src/dsa.cpp
index e0d0519c169..4574fe5ebd8 100644
--- a/extra/yassl/taocrypt/src/dsa.cpp
+++ b/extra/yassl/taocrypt/src/dsa.cpp
@@ -20,6 +20,7 @@
*/
+#include "runtime.hpp"
#include "dsa.hpp"
#include "sha.hpp"
#include "asn.hpp"
diff --git a/extra/yassl/taocrypt/src/file.cpp b/extra/yassl/taocrypt/src/file.cpp
index 75df80608ae..4d48b9e7bca 100644
--- a/extra/yassl/taocrypt/src/file.cpp
+++ b/extra/yassl/taocrypt/src/file.cpp
@@ -22,6 +22,7 @@
/* file.cpp implements File Sources and Sinks
*/
+#include "runtime.hpp"
#include "file.hpp"
diff --git a/extra/yassl/taocrypt/src/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp
index ebfefb027b3..71324b04b92 100644
--- a/extra/yassl/taocrypt/src/integer.cpp
+++ b/extra/yassl/taocrypt/src/integer.cpp
@@ -35,7 +35,9 @@
#endif
-#if defined(_MSC_VER) && defined(_WIN64) // 64 bit X overflow intrinsic
+// 64bit multiply overflow intrinsic
+#if defined(_MSC_VER) && defined(_WIN64) && !defined(__INTEL_COMPILER) && \
+ !defined(TAOCRYPT_NATIVE_DWORD_AVAILABLE)
#ifdef __ia64__
#define myUMULH __UMULH
#elif __x86_64__
@@ -3956,7 +3958,8 @@ Integer CRT(const Integer &xp, const Integer &p, const Integer &xq,
return p * (u * (xq-xp) % q) + xp;
}
-#ifdef __GNUC__
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
#ifndef TAOCRYPT_NATIVE_DWORD_AVAILABLE
template hword DivideThreeWordsByTwo<hword, Word>(hword*, hword, hword, Word*);
#endif
diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp
index 6a801a9995a..ef051332098 100644
--- a/extra/yassl/taocrypt/src/misc.cpp
+++ b/extra/yassl/taocrypt/src/misc.cpp
@@ -22,34 +22,43 @@
/* based on Wei Dai's misc.cpp from CryptoPP */
+#include "runtime.hpp"
#include "misc.hpp"
#include <new> // for NewHandler
void* operator new(size_t sz, TaoCrypt::new_t)
{
+#ifdef YASSL_PURE_C
void* ptr = malloc(sz ? sz : 1);
if (!ptr) abort();
return ptr;
+#else
+ return ::operator new(sz);
+#endif
}
-void* operator new[](size_t sz, TaoCrypt::new_t)
-{
- void* ptr = malloc(sz ? sz : 1);
- if (!ptr) abort();
-
- return ptr;
-}
void operator delete(void* ptr, TaoCrypt::new_t)
{
+#ifdef YASSL_PURE_C
if (ptr) free(ptr);
+#else
+ ::operator delete(ptr);
+#endif
}
-void operator delete[](void* ptr, TaoCrypt::new_t)
+
+void* operator new[](size_t sz, TaoCrypt::new_t nt)
{
- if (ptr) free(ptr);
+ return ::operator new(sz, nt);
+}
+
+
+void operator delete[](void* ptr, TaoCrypt::new_t nt)
+{
+ ::operator delete(ptr, nt);
}
diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp
index 69fb180720a..e1e6416eb00 100644
--- a/extra/yassl/taocrypt/src/random.cpp
+++ b/extra/yassl/taocrypt/src/random.cpp
@@ -24,6 +24,7 @@
specific seed, switch to /dev/random for more security but may block
*/
+#include "runtime.hpp"
#include "random.hpp"
#if defined(_WIN32)
diff --git a/extra/yassl/taocrypt/src/rsa.cpp b/extra/yassl/taocrypt/src/rsa.cpp
index 4c7c45b8ffe..021fd992b5c 100644
--- a/extra/yassl/taocrypt/src/rsa.cpp
+++ b/extra/yassl/taocrypt/src/rsa.cpp
@@ -21,6 +21,7 @@
/* based on Wei Dai's rsa.cpp from CryptoPP */
+#include "runtime.hpp"
#include "rsa.hpp"
#include "asn.hpp"
#include "modarith.hpp"
diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp
index 81a8273c5c3..9a3c12badfc 100644
--- a/extra/yassl/taocrypt/src/template_instnt.cpp
+++ b/extra/yassl/taocrypt/src/template_instnt.cpp
@@ -1,14 +1,42 @@
+/* template_instnt.cpp
+ *
+ * Copyright (C) 2003 Sawtooth Consulting Ltd.
+ *
+ * This file is part of yaSSL.
+ *
+ * yaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * yaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* Explicit template instantiation requests
+ */
+
+
#include "integer.hpp"
#include "rsa.hpp"
#include "algebra.hpp"
#include "vector.hpp"
#include "hash.hpp"
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace TaoCrypt {
+
#if defined(SSE2_INTRINSICS_AVAILABLE)
template AlignedAllocator<unsigned int>::pointer StdReallocate<unsigned int, AlignedAllocator<unsigned int> >(AlignedAllocator<unsigned int>&, unsigned int*, AlignedAllocator<unsigned int>::size_type, AlignedAllocator<unsigned int>::size_type, bool);
#endif
+
template class RSA_Decryptor<RSA_BlockType2>;
template class RSA_Encryptor<RSA_BlockType1>;
template class RSA_Encryptor<RSA_BlockType2>;
@@ -17,10 +45,12 @@ template void tcArrayDelete<byte>(byte*);
template AllocatorWithCleanup<byte>::pointer StdReallocate<byte, AllocatorWithCleanup<byte> >(AllocatorWithCleanup<byte>&, byte*, AllocatorWithCleanup<byte>::size_type, AllocatorWithCleanup<byte>::size_type, bool);
template void tcArrayDelete<word>(word*);
template AllocatorWithCleanup<word>::pointer StdReallocate<word, AllocatorWithCleanup<word> >(AllocatorWithCleanup<word>&, word*, AllocatorWithCleanup<word>::size_type, AllocatorWithCleanup<word>::size_type, bool);
+
#ifndef TAOCRYPT_SLOW_WORD64 // defined when word != word32
template void tcArrayDelete<word32>(word32*);
template AllocatorWithCleanup<word32>::pointer StdReallocate<word32, AllocatorWithCleanup<word32> >(AllocatorWithCleanup<word32>&, word32*, AllocatorWithCleanup<word32>::size_type, AllocatorWithCleanup<word32>::size_type, bool);
#endif
+
template void tcArrayDelete<char>(char*);
}
diff --git a/heap/Makefile.am b/heap/Makefile.am
index 2262fa3d5b1..567c7774751 100644
--- a/heap/Makefile.am
+++ b/heap/Makefile.am
@@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
LDADD = libheap.a ../mysys/libmysys.a ../dbug/libdbug.a \
../strings/libmystrings.a
pkglib_LIBRARIES = libheap.a
diff --git a/heap/hp_hash.c b/heap/hp_hash.c
index 9e4636ebdc0..d643f776731 100644
--- a/heap/hp_hash.c
+++ b/heap/hp_hash.c
@@ -552,9 +552,9 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2,
if (cs->mbmaxlen > 1)
{
uint char_length= seg->length / cs->mbmaxlen;
- char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
+ char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length1);
set_if_smaller(char_length1, seg->length);
- char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
+ char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length2);
set_if_smaller(char_length2, seg->length);
}
diff --git a/include/config-netware.h b/include/config-netware.h
index 4a6dc3b1bb9..906f557f608 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -46,11 +46,21 @@ extern "C" {
#undef HAVE_SYS_MMAN_H
#undef HAVE_SYNCH_H
#undef HAVE_MMAP
+
#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
#define HAVE_PTHREAD_SIGMASK 1
#define HAVE_PTHREAD_YIELD_ZERO_ARG 1
#define HAVE_BROKEN_REALPATH 1
+#undef HAVE_POSIX_SIGNALS
+#undef HAVE_PTHREAD_ATTR_SETSCOPE
+#undef HAVE_ALLOC_A
+#undef HAVE_FINITE
+#undef HAVE_GETPWNAM
+#undef HAVE_GETPWUID
+#undef HAVE_PTHREAD_SETSCHEDPARAM
+#undef HAVE_READLINK
+#undef HAVE_STPCPY
/* no libc crypt() function */
#ifdef HAVE_OPENSSL
#define HAVE_CRYPT 1
diff --git a/include/my_base.h b/include/my_base.h
index 25fa683744e..c76cf8c604e 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -367,6 +367,7 @@ enum ha_base_keytype {
#define HA_STATE_EXTEND_BLOCK 2048
#define HA_STATE_RNEXT_SAME 4096 /* rnext_same was called */
+/* myisampack expects no more than 32 field types. */
enum en_fieldtype {
FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE,
FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO,
diff --git a/include/my_bitmap.h b/include/my_bitmap.h
index 4caa3b85456..84a5d8bd18a 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -45,6 +45,8 @@ extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size);
extern my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_is_set_all(const MY_BITMAP *map);
extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2);
+extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit);
+extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit);
extern uint bitmap_set_next(MY_BITMAP *map);
extern uint bitmap_get_first(const MY_BITMAP *map);
extern uint bitmap_bits_set(const MY_BITMAP *map);
diff --git a/include/my_global.h b/include/my_global.h
index 04d33be38b4..61850931a8e 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -295,10 +295,8 @@ C_MODE_END
#include <alloca.h>
#endif
#ifdef HAVE_ATOMIC_ADD
-#if defined(__ia64__)
#define new my_arg_new
#define need_to_restore_new 1
-#endif
C_MODE_START
#include <asm/atomic.h>
C_MODE_END
@@ -341,6 +339,11 @@ C_MODE_END
#undef HAVE_FINITE
#undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */
#undef LONGLONG_MAX /* standard system library 'limits.h' */
+#ifdef __cplusplus
+#define HAVE_RINT /* rint() and isnan() functions are not */
+#define rint(a) std::rint(a) /* visible in C++ scope due to an error */
+#define isnan(a) std::isnan(a) /* in the usr/include/math.h on QNX */
+#endif
#endif
/* We can not live without the following defines */
@@ -393,10 +396,7 @@ int __void__;
#endif
/* Define some useful general macros */
-#if defined(__cplusplus) && defined(__GNUC__)
-#define max(a, b) ((a) >? (b))
-#define min(a, b) ((a) <? (b))
-#elif !defined(max)
+#if !defined(max)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
@@ -830,7 +830,7 @@ typedef off_t os_off_t;
#define socket_errno WSAGetLastError()
#define SOCKET_EINTR WSAEINTR
#define SOCKET_EAGAIN WSAEINPROGRESS
-#define SOCKET_EWOULDBLOCK WSAEINPROGRESS
+#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#elif defined(OS2)
diff --git a/include/my_sys.h b/include/my_sys.h
index ee4312be058..e31659c0652 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -263,6 +263,7 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io,
extern char wild_many,wild_one,wild_prefix;
extern const char *charsets_dir;
extern char *defaults_extra_file;
+extern const char *defaults_instance;
extern my_bool timed_mutexes;
@@ -865,6 +866,9 @@ 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);
+extern ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info,
+ char *to, ulong to_length,
+ const char *from, ulong length);
extern void thd_increment_bytes_sent(ulong length);
extern void thd_increment_bytes_received(ulong length);
diff --git a/include/mysql.h b/include/mysql.h
index 84284fa0661..2ba41e6d367 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -218,6 +218,18 @@ enum mysql_rpl_type
MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN
};
+typedef struct character_set
+{
+ unsigned int number; /* character set number */
+ unsigned int state; /* character set state */
+ const char *csname; /* collation name */
+ const char *name; /* character set name */
+ const char *comment; /* comment */
+ const char *dir; /* character set directory */
+ unsigned int mbminlen; /* min. length for multibyte strings */
+ unsigned int mbmaxlen; /* max. length for multibyte strings */
+} MY_CHARSET_INFO;
+
struct st_mysql_methods;
typedef struct st_mysql
@@ -384,7 +396,7 @@ unsigned int STDCALL mysql_warning_count(MYSQL *mysql);
const char * STDCALL mysql_info(MYSQL *mysql);
unsigned long STDCALL mysql_thread_id(MYSQL *mysql);
const char * STDCALL mysql_character_set_name(MYSQL *mysql);
-int STDCALL mysql_set_character_set(MYSQL *mysql, char *csname);
+int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname);
MYSQL * STDCALL mysql_init(MYSQL *mysql);
my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
@@ -418,6 +430,8 @@ my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
unsigned long length);
my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
unsigned long length);
+void STDCALL mysql_get_character_set_info(MYSQL *mysql,
+ MY_CHARSET_INFO *charset);
/* local infile support */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index c608a2e7724..969fba4a433 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -48,8 +48,8 @@ enum enum_server_command
COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
- COM_PREPARE, COM_EXECUTE, COM_LONG_DATA, COM_CLOSE_STMT,
- COM_RESET_STMT, COM_SET_OPTION, COM_FETCH,
+ COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE,
+ COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH,
/* don't forget to update const char *command_name[] in sql_parse.cc */
/* Must be last */
@@ -137,17 +137,18 @@ enum enum_server_command
#define SERVER_QUERY_NO_GOOD_INDEX_USED 16
#define SERVER_QUERY_NO_INDEX_USED 32
/*
- The server was able to fulfill client request and open read-only
- non-scrollable cursor for the query. This flag comes in server
- status with reply to COM_EXECUTE and COM_EXECUTE_DIRECT commands.
+ The server was able to fulfill the clients request and opened a
+ read-only non-scrollable cursor for a query. This flag comes
+ in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
*/
#define SERVER_STATUS_CURSOR_EXISTS 64
/*
- This flag is sent with last row of read-only cursor, in reply to
- COM_FETCH command.
+ This flag is sent when a read-only cursor is exhausted, in reply to
+ COM_STMT_FETCH command.
*/
#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */
+#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
#define MYSQL_ERRMSG_SIZE 512
#define NET_READ_TIMEOUT 30 /* Timeout on read */
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c
index 1744fc36f4d..c27fb73ff8d 100644
--- a/innobase/btr/btr0btr.c
+++ b/innobase/btr/btr0btr.c
@@ -20,6 +20,7 @@ Created 6/2/1994 Heikki Tuuri
#include "rem0cmp.h"
#include "lock0lock.h"
#include "ibuf0ibuf.h"
+#include "trx0trx.h"
/*
Latching strategy of the InnoDB B-tree
@@ -137,13 +138,13 @@ btr_root_get(
ulint space;
ulint root_page_no;
page_t* root;
- ibool comp = UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp;
space = dict_tree_get_space(tree);
root_page_no = dict_tree_get_page(tree);
root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(root) == comp);
+ ut_a((ibool)!!page_is_comp(root) ==
+ UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
return(root);
}
@@ -163,21 +164,19 @@ btr_get_prev_user_rec(
page_t* page;
page_t* prev_page;
ulint prev_page_no;
- rec_t* prev_rec;
ulint space;
- page = buf_frame_align(rec);
-
- if (page_get_infimum_rec(page) != rec) {
+ if (!page_rec_is_infimum(rec)) {
- prev_rec = page_rec_get_prev(rec);
+ rec_t* prev_rec = page_rec_get_prev(rec);
- if (page_get_infimum_rec(page) != prev_rec) {
+ if (!page_rec_is_infimum(prev_rec)) {
return(prev_rec);
}
}
+ page = buf_frame_align(rec);
prev_page_no = btr_page_get_prev(page, mtr);
space = buf_frame_get_space_id(page);
@@ -192,9 +191,7 @@ btr_get_prev_user_rec(
MTR_MEMO_PAGE_X_FIX)));
ut_a(page_is_comp(prev_page) == page_is_comp(page));
- prev_rec = page_rec_get_prev(page_get_supremum_rec(prev_page));
-
- return(prev_rec);
+ return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
}
return(NULL);
@@ -215,21 +212,19 @@ btr_get_next_user_rec(
page_t* page;
page_t* next_page;
ulint next_page_no;
- rec_t* next_rec;
ulint space;
- page = buf_frame_align(rec);
-
- if (page_get_supremum_rec(page) != rec) {
+ if (!page_rec_is_supremum(rec)) {
- next_rec = page_rec_get_next(rec);
+ rec_t* next_rec = page_rec_get_next(rec);
- if (page_get_supremum_rec(page) != next_rec) {
+ if (!page_rec_is_supremum(next_rec)) {
return(next_rec);
}
}
+ page = buf_frame_align(rec);
next_page_no = btr_page_get_next(page, mtr);
space = buf_frame_get_space_id(page);
@@ -244,9 +239,7 @@ btr_get_next_user_rec(
MTR_MEMO_PAGE_X_FIX)));
ut_a(page_is_comp(next_page) == page_is_comp(page));
- next_rec = page_rec_get_next(page_get_infimum_rec(next_page));
-
- return(next_rec);
+ return(page_rec_get_next(page_get_infimum_rec(next_page)));
}
return(NULL);
@@ -573,8 +566,7 @@ btr_page_get_father_for_rec(
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
MTR_MEMO_X_LOCK));
- ut_a(user_rec != page_get_supremum_rec(page));
- ut_a(user_rec != page_get_infimum_rec(page));
+ ut_a(page_rec_is_user_rec(user_rec));
ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page));
@@ -598,6 +590,7 @@ btr_page_get_father_for_rec(
if (btr_node_ptr_get_child_page_no(node_ptr, offsets) !=
buf_frame_get_page_no(page)) {
+ rec_t* print_rec;
fputs("InnoDB: Dump of the child page:\n", stderr);
buf_page_print(buf_frame_align(page));
fputs("InnoDB: Dump of the parent page:\n", stderr);
@@ -612,11 +605,10 @@ btr_page_get_father_for_rec(
(ulong)
btr_node_ptr_get_child_page_no(node_ptr, offsets),
(ulong) buf_frame_get_page_no(page));
- offsets = rec_get_offsets(page_rec_get_next(
- page_get_infimum_rec(page)), index,
+ print_rec = page_rec_get_next(page_get_infimum_rec(page));
+ offsets = rec_get_offsets(print_rec, index,
offsets, ULINT_UNDEFINED, &heap);
- page_rec_print(page_rec_get_next(page_get_infimum_rec(page)),
- offsets);
+ page_rec_print(print_rec, offsets);
offsets = rec_get_offsets(node_ptr, index, offsets,
ULINT_UNDEFINED, &heap);
page_rec_print(node_ptr, offsets);
@@ -663,7 +655,7 @@ btr_create(
ulint type, /* in: type of the index */
ulint space, /* in: space where created */
dulint index_id,/* in: index id */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr) /* in: mini-transaction handle */
{
ulint page_no;
@@ -854,11 +846,12 @@ btr_page_reorganize_low(
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
+ ut_ad(!!page_is_comp(page) == index->table->comp);
data_size1 = page_get_data_size(page);
max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
/* Write the log record */
- mlog_open_and_write_index(mtr, page, index, index->table->comp
+ mlog_open_and_write_index(mtr, page, index, page_is_comp(page)
? MLOG_COMP_PAGE_REORGANIZE
: MLOG_PAGE_REORGANIZE, 0);
@@ -877,7 +870,7 @@ btr_page_reorganize_low(
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
- page_create(page, mtr, index->table->comp);
+ page_create(page, mtr, page_is_comp(page));
buf_block_align(page)->check_index_page_at_flush = TRUE;
/* Copy the records from the temporary space to the recreated page;
@@ -1070,7 +1063,7 @@ btr_root_raise_and_insert(
as there is no lower alphabetical limit to records in the leftmost
node of a level: */
- btr_set_min_rec_mark(node_ptr_rec, cursor->index->table->comp, mtr);
+ btr_set_min_rec_mark(node_ptr_rec, page_is_comp(root), mtr);
/* Free the memory heap */
mem_heap_free(heap);
@@ -1151,7 +1144,6 @@ btr_page_get_split_rec_to_right(
{
page_t* page;
rec_t* insert_point;
- rec_t* supremum;
page = btr_cur_get_page(cursor);
insert_point = btr_cur_get_rec(cursor);
@@ -1160,13 +1152,23 @@ btr_page_get_split_rec_to_right(
the previous insert on the same page, we assume that there is a
pattern of sequential inserts here. */
- if (page_header_get_ptr(page, PAGE_LAST_INSERT) == insert_point) {
+ if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
+ == insert_point)) {
+
+ rec_t* next_rec;
+
+ next_rec = page_rec_get_next(insert_point);
- supremum = page_get_supremum_rec(page);
-
- if (page_rec_get_next(insert_point) != supremum
- && page_rec_get_next(page_rec_get_next(insert_point))
- != supremum) {
+ if (page_rec_is_supremum(next_rec)) {
+split_at_new:
+ /* Split at the new record to insert */
+ *split_rec = NULL;
+ } else {
+ rec_t* next_next_rec = page_rec_get_next(next_rec);
+ if (page_rec_is_supremum(next_next_rec)) {
+
+ goto split_at_new;
+ }
/* If there are >= 2 user records up from the insert
point, split all but 1 off. We want to keep one because
@@ -1175,12 +1177,8 @@ btr_page_get_split_rec_to_right(
search position just by looking at the records on this
page. */
- *split_rec = page_rec_get_next(
- page_rec_get_next(insert_point));
- } else {
- /* Else split at the new record to insert */
- *split_rec = NULL;
- }
+ *split_rec = next_next_rec;
+ }
return(TRUE);
}
@@ -1220,7 +1218,7 @@ btr_page_get_sure_split_rec(
page = btr_cur_get_page(cursor);
insert_size = rec_get_converted_size(cursor->index, tuple);
- free_space = page_get_free_space_of_empty(cursor->index->table->comp);
+ free_space = page_get_free_space_of_empty(page_is_comp(page));
/* free_space is now the free space of a created new page */
@@ -1276,21 +1274,22 @@ btr_page_get_sure_split_rec(
supremum record of page */
if (rec == ins_rec) {
- next_rec = NULL;
+ rec = NULL;
+
+ goto func_exit;
} else if (rec == NULL) {
next_rec = page_rec_get_next(ins_rec);
} else {
next_rec = page_rec_get_next(rec);
}
- if (next_rec != page_get_supremum_rec(page)) {
- if (heap) {
- mem_heap_free(heap);
- }
- return(next_rec);
+ ut_ad(next_rec);
+ if (!page_rec_is_supremum(next_rec)) {
+ rec = next_rec;
}
}
- if (heap) {
+func_exit:
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(rec);
@@ -1329,13 +1328,12 @@ btr_page_insert_fits(
ut_ad(!split_rec == !offsets);
ut_ad(!offsets
- || cursor->index->table->comp == rec_offs_comp(offsets));
+ || !page_is_comp(page) == !rec_offs_comp(offsets));
ut_ad(!offsets
|| rec_offs_validate(split_rec, cursor->index, offsets));
- ut_ad(page_is_comp(page) == cursor->index->table->comp);
insert_size = rec_get_converted_size(cursor->index, tuple);
- free_space = page_get_free_space_of_empty(cursor->index->table->comp);
+ free_space = page_get_free_space_of_empty(page_is_comp(page));
/* free_space is now the free space of a created new page */
@@ -1832,14 +1830,15 @@ void
btr_set_min_rec_mark_log(
/*=====================*/
rec_t* rec, /* in: record */
- ibool comp, /* TRUE=compact record format */
+ ulint comp, /* nonzero=compact record format */
mtr_t* mtr) /* in: mtr */
{
mlog_write_initial_log_record(rec,
comp ? MLOG_COMP_REC_MIN_MARK : MLOG_REC_MIN_MARK, mtr);
/* Write rec offset as a 2-byte ulint */
- mlog_catenate_ulint(mtr, rec - buf_frame_align(rec), MLOG_2BYTES);
+ mlog_catenate_ulint(mtr, ut_align_offset(rec, UNIV_PAGE_SIZE),
+ MLOG_2BYTES);
}
/********************************************************************
@@ -1852,7 +1851,7 @@ btr_parse_set_min_rec_mark(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -1864,6 +1863,8 @@ btr_parse_set_min_rec_mark(
}
if (page) {
+ ut_a(!page_is_comp(page) == !comp);
+
rec = page + mach_read_from_2(ptr);
btr_set_min_rec_mark(rec, comp, mtr);
@@ -1879,7 +1880,7 @@ void
btr_set_min_rec_mark(
/*=================*/
rec_t* rec, /* in: record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr) /* in: mtr */
{
ulint info_bits;
@@ -2008,11 +2009,12 @@ btr_compress(
ulint max_ins_size;
ulint max_ins_size_reorg;
ulint level;
- ibool comp = cursor->index->table->comp;
+ ulint comp;
page = btr_cur_get_page(cursor);
tree = btr_cur_get_tree(cursor);
- ut_a(comp == page_is_comp(page));
+ comp = page_is_comp(page);
+ ut_a((ibool)!!comp == cursor->index->table->comp);
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
MTR_MEMO_X_LOCK));
@@ -2055,7 +2057,7 @@ btr_compress(
n_recs = page_get_n_recs(page);
data_size = page_get_data_size(page);
- ut_a(page_is_comp(merge_page) == page_is_comp(page));
+ ut_a(page_is_comp(merge_page) == comp);
max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
merge_page, n_recs);
@@ -2108,7 +2110,7 @@ btr_compress(
rec_get_offsets(node_ptr, cursor->index,
offsets_, ULINT_UNDEFINED, &heap),
right_page_no, mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
btr_node_ptr_delete(tree, merge_page, mtr);
@@ -2250,10 +2252,9 @@ btr_discard_page(
node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page));
- ut_ad(node_ptr != page_get_supremum_rec(merge_page));
+ ut_ad(page_rec_is_user_rec(node_ptr));
- btr_set_min_rec_mark(node_ptr,
- cursor->index->table->comp, mtr);
+ btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr);
}
btr_node_ptr_delete(tree, page, mtr);
@@ -2274,6 +2275,7 @@ btr_discard_page(
ut_ad(btr_check_node_ptr(tree, merge_page, mtr));
}
+#ifdef UNIV_BTR_PRINT
/*****************************************************************
Prints size info of a B-tree. */
@@ -2401,14 +2403,15 @@ btr_print_tree(
root = btr_root_get(tree, &mtr);
btr_print_recursive(tree, root, width, &heap, &offsets, &mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
mtr_commit(&mtr);
- btr_validate_tree(tree);
+ btr_validate_tree(tree, NULL);
}
+#endif /* UNIV_BTR_PRINT */
/****************************************************************
Checks that the node pointer to a page is appropriate. */
@@ -2496,8 +2499,8 @@ btr_index_rec_validate(
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
page = buf_frame_align(rec);
-
- if (index->type & DICT_UNIVERSAL) {
+
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
/* The insert buffer index tree can contain records from any
other index: we cannot check the number of fields or
their length */
@@ -2505,9 +2508,18 @@ btr_index_rec_validate(
return(TRUE);
}
+ if (UNIV_UNLIKELY((ibool)!!page_is_comp(page) != index->table->comp)) {
+ btr_index_rec_validate_report(page, rec, index);
+ fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
+ (ulong) !!page_is_comp(page),
+ (ulong) index->table->comp);
+ return(FALSE);
+ }
+
n = dict_index_get_n_fields(index);
- if (!index->table->comp && rec_get_n_fields_old(rec) != n) {
+ if (!page_is_comp(page)
+ && UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
btr_index_rec_validate_report(page, rec, index);
fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
(ulong) rec_get_n_fields_old(rec), (ulong) n);
@@ -2554,14 +2566,14 @@ btr_index_rec_validate(
rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(FALSE);
}
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(TRUE);
@@ -2649,6 +2661,7 @@ btr_validate_level(
/*===============*/
/* out: TRUE if ok */
dict_tree_t* tree, /* in: index tree */
+ trx_t* trx, /* in: transaction or NULL */
ulint level) /* in: level number */
{
ulint space;
@@ -2696,6 +2709,11 @@ btr_validate_level(
/* Now we are on the desired level. Loop through the pages on that
level. */
loop:
+ if (trx_is_interrupted(trx)) {
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+ return(ret);
+ }
mem_heap_empty(heap);
offsets = offsets2 = NULL;
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
@@ -2765,7 +2783,7 @@ loop:
if (level > 0 && left_page_no == FIL_NULL) {
ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
page_rec_get_next(page_get_infimum_rec(page)),
- index->table->comp));
+ page_is_comp(page)));
}
if (buf_frame_get_page_no(page) != dict_tree_get_page(tree)) {
@@ -2921,7 +2939,7 @@ node_ptr_fails:
mtr_commit(&mtr);
if (right_page_no != FIL_NULL) {
- ibool comp = page_is_comp(page);
+ ulint comp = page_is_comp(page);
mtr_start(&mtr);
page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
@@ -2941,7 +2959,8 @@ ibool
btr_validate_tree(
/*==============*/
/* out: TRUE if ok */
- dict_tree_t* tree) /* in: tree */
+ dict_tree_t* tree, /* in: tree */
+ trx_t* trx) /* in: transaction or NULL */
{
mtr_t mtr;
page_t* root;
@@ -2954,9 +2973,8 @@ btr_validate_tree(
root = btr_root_get(tree, &mtr);
n = btr_page_get_level(root, &mtr);
- for (i = 0; i <= n; i++) {
-
- if (!btr_validate_level(tree, n - i)) {
+ for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
+ if (!btr_validate_level(tree, trx, n - i)) {
mtr_commit(&mtr);
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index e093c911f22..f81cce5b8e9 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -36,11 +36,11 @@ Created 10/16/1994 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "lock0lock.h"
+#ifdef UNIV_DEBUG
/* If the following is set to TRUE, this module prints a lot of
trace information of individual record operations */
ibool btr_cur_print_record_ops = FALSE;
-
-ulint btr_cur_rnd = 0;
+#endif /* UNIV_DEBUG */
ulint btr_cur_n_non_sea = 0;
ulint btr_cur_n_sea = 0;
@@ -316,7 +316,9 @@ btr_cur_search_to_nth_level(
if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
&& !estimate
+#ifdef PAGE_CUR_LE_OR_EXTENDS
&& mode != PAGE_CUR_LE_OR_EXTENDS
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
&& srv_use_adaptive_hash_indexes
&& btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor,
@@ -390,9 +392,12 @@ btr_cur_search_to_nth_level(
page_mode = PAGE_CUR_LE;
break;
default:
- ut_ad(mode == PAGE_CUR_L
- || mode == PAGE_CUR_LE
+#ifdef PAGE_CUR_LE_OR_EXTENDS
+ ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
|| mode == PAGE_CUR_LE_OR_EXTENDS);
+#else /* PAGE_CUR_LE_OR_EXTENDS */
+ ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE);
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
page_mode = mode;
break;
}
@@ -431,7 +436,7 @@ retry_page_get:
cursor->thr)) {
/* Insertion to the insert buffer succeeded */
cursor->flag = BTR_CUR_INSERT_TO_IBUF;
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return;
@@ -505,8 +510,9 @@ retry_page_get:
if (level > 0) {
/* x-latch the page */
- ut_a(page_is_comp(btr_page_get(space,
- page_no, RW_X_LATCH, mtr))
+ page = btr_page_get(space,
+ page_no, RW_X_LATCH, mtr);
+ ut_a((ibool)!!page_is_comp(page)
== index->table->comp);
}
@@ -525,7 +531,7 @@ retry_page_get:
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -681,7 +687,7 @@ btr_cur_open_at_index_side(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -762,7 +768,7 @@ btr_cur_open_at_rnd_pos(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -879,6 +885,7 @@ btr_cur_ins_lock_and_undo(
return(DB_SUCCESS);
}
+#ifdef UNIV_DEBUG
/*****************************************************************
Report information about a transaction. */
static
@@ -896,6 +903,7 @@ btr_cur_trx_report(
dict_index_name_print(stderr, trx, index);
putc('\n', stderr);
}
+#endif /* UNIV_DEBUG */
/*****************************************************************
Tries to perform an insert to a page in an index tree, next to cursor.
@@ -945,12 +953,13 @@ btr_cur_optimistic_insert(
fputs("InnoDB: Error in a tuple to insert into ", stderr);
dict_index_name_print(stderr, thr_get_trx(thr), index);
}
-
+#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), index, "insert into ");
dtuple_print(stderr, entry);
}
-
+#endif /* UNIV_DEBUG */
+
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
max_size = page_get_max_insert_size_after_reorganize(page, 1);
@@ -961,7 +970,7 @@ calculate_sizes_again:
rec_size = rec_get_converted_size(index, entry);
if (rec_size >=
- ut_min(page_get_free_space_of_empty(index->table->comp) / 2,
+ ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2,
REC_MAX_DATA_SIZE)) {
/* The record is so big that we have to store some fields
@@ -1027,7 +1036,7 @@ calculate_sizes_again:
*rec = page_cur_insert_rec_low(page_cursor, entry, index,
NULL, NULL, mtr);
- if (!(*rec)) {
+ if (UNIV_UNLIKELY(!(*rec))) {
/* If the record did not fit, reorganize */
btr_page_reorganize(page, index, mtr);
@@ -1039,7 +1048,7 @@ calculate_sizes_again:
*rec = page_cur_tuple_insert(page_cursor, entry, index, mtr);
- if (!*rec) {
+ if (UNIV_UNLIKELY(!*rec)) {
fputs("InnoDB: Error: cannot insert tuple ", stderr);
dtuple_print(stderr, entry);
fputs(" into ", stderr);
@@ -1166,7 +1175,7 @@ btr_cur_pessimistic_insert(
}
if (rec_get_converted_size(index, entry) >=
- ut_min(page_get_free_space_of_empty(index->table->comp) / 2,
+ ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2,
REC_MAX_DATA_SIZE)) {
/* The record is so big that we have to store some fields
@@ -1261,7 +1270,7 @@ btr_cur_upd_lock_and_undo(
err = lock_clust_rec_modify_check_and_lock(flags, rec, index,
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap), thr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
if (err != DB_SUCCESS) {
@@ -1293,9 +1302,11 @@ btr_cur_update_in_place_log(
mtr_t* mtr) /* in: mtr */
{
byte* log_ptr;
+ page_t* page = ut_align_down(rec, UNIV_PAGE_SIZE);
ut_ad(flags < 256);
+ ut_ad(!!page_is_comp(page) == index->table->comp);
- log_ptr = mlog_open_and_write_index(mtr, rec, index, index->table->comp
+ log_ptr = mlog_open_and_write_index(mtr, rec, index, page_is_comp(page)
? MLOG_COMP_REC_UPDATE_IN_PLACE
: MLOG_REC_UPDATE_IN_PLACE,
1 + DATA_ROLL_PTR_LEN + 14 + 2 + MLOG_BUF_MARGIN);
@@ -1317,7 +1328,7 @@ btr_cur_update_in_place_log(
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
mtr);
- mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
+ mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
log_ptr += 2;
row_upd_index_write_log(update, log_ptr, mtr);
@@ -1374,18 +1385,12 @@ btr_cur_parse_update_in_place(
ptr = row_upd_index_parse(ptr, end_ptr, heap, &update);
- if (ptr == NULL) {
- mem_heap_free(heap);
-
- return(NULL);
- }
-
- if (!page) {
- mem_heap_free(heap);
+ if (!ptr || !page) {
- return(ptr);
+ goto func_exit;
}
-
+
+ ut_a((ibool)!!page_is_comp(page) == index->table->comp);
rec = page + rec_offset;
/* We do not need to reserve btr_search_latch, as the page is only
@@ -1400,6 +1405,7 @@ btr_cur_parse_update_in_place(
row_upd_rec_in_place(rec, offsets, update);
+func_exit:
mem_heap_free(heap);
return(ptr);
@@ -1429,7 +1435,7 @@ btr_cur_update_in_place(
rec_t* rec;
dulint roll_ptr = ut_dulint_zero;
trx_t* trx;
- ibool was_delete_marked;
+ ulint was_delete_marked;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -1437,27 +1443,30 @@ btr_cur_update_in_place(
rec = btr_cur_get_rec(cursor);
index = cursor->index;
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
trx = thr_get_trx(thr);
- heap = mem_heap_create(100);
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-
+#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(trx, index, "update ");
rec_print_new(stderr, rec, offsets);
}
+#endif /* UNIV_DEBUG */
/* Do lock checking and undo logging */
err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
thr, &roll_ptr);
- if (err != DB_SUCCESS) {
+ if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
}
block = buf_block_align(rec);
+ ut_ad(!!page_is_comp(buf_block_get_frame(block))
+ == index->table->comp);
if (block->is_hashed) {
/* The function row_upd_changes_ord_field_binary works only
@@ -1481,7 +1490,8 @@ btr_cur_update_in_place(
/* FIXME: in a mixed tree, all records may not have enough ordering
fields for btr search: */
- was_delete_marked = rec_get_deleted_flag(rec, index->table->comp);
+ was_delete_marked = rec_get_deleted_flag(rec,
+ page_is_comp(buf_block_get_frame(block)));
row_upd_rec_in_place(rec, offsets, update);
@@ -1491,14 +1501,15 @@ btr_cur_update_in_place(
btr_cur_update_in_place_log(flags, rec, index, update, trx, roll_ptr,
mtr);
- if (was_delete_marked && !rec_get_deleted_flag(rec, index->table->comp)) {
+ if (was_delete_marked && !rec_get_deleted_flag(rec,
+ page_is_comp(buf_block_get_frame(block)))) {
/* The new updated record owns its possible externally
stored fields */
btr_cur_unmark_extern_fields(rec, mtr, offsets);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(DB_SUCCESS);
@@ -1547,14 +1558,17 @@ btr_cur_optimistic_update(
page = btr_cur_get_page(cursor);
rec = btr_cur_get_rec(cursor);
index = cursor->index;
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
heap = mem_heap_create(1024);
offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), index, "update ");
rec_print_new(stderr, rec, offsets);
}
+#endif /* UNIV_DEBUG */
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
@@ -1596,8 +1610,8 @@ btr_cur_optimistic_update(
old_rec_size = rec_offs_size(offsets);
new_rec_size = rec_get_converted_size(index, new_entry);
- if (new_rec_size >=
- page_get_free_space_of_empty(index->table->comp) / 2) {
+ if (UNIV_UNLIKELY(new_rec_size >= page_get_free_space_of_empty(
+ page_is_comp(page)) / 2)) {
mem_heap_free(heap);
@@ -1607,8 +1621,9 @@ btr_cur_optimistic_update(
max_size = old_rec_size
+ page_get_max_insert_size_after_reorganize(page, 1);
- if (page_get_data_size(page) - old_rec_size + new_rec_size
- < BTR_CUR_PAGE_COMPRESS_LIMIT) {
+ if (UNIV_UNLIKELY(page_get_data_size(page)
+ - old_rec_size + new_rec_size
+ < BTR_CUR_PAGE_COMPRESS_LIMIT)) {
/* The page would become too empty */
@@ -1644,7 +1659,7 @@ btr_cur_optimistic_update(
explicit locks on rec, before deleting rec (see the comment in
.._pessimistic_update). */
- lock_rec_store_on_page_infimum(rec);
+ lock_rec_store_on_page_infimum(page, rec);
btr_search_update_hash_on_delete(cursor);
@@ -1665,7 +1680,7 @@ btr_cur_optimistic_update(
ut_a(rec); /* <- We calculated above the insert would fit */
- if (!rec_get_deleted_flag(rec, index->table->comp)) {
+ if (!rec_get_deleted_flag(rec, page_is_comp(page))) {
/* The new inserted record owns its possible externally
stored fields */
@@ -1814,7 +1829,7 @@ btr_cur_pessimistic_update(
}
success = fsp_reserve_free_extents(&n_reserved,
- cursor->index->space,
+ index->space,
n_extents, reserve_flag, mtr);
if (!success) {
err = DB_OUT_OF_FILE_SPACE;
@@ -1858,14 +1873,14 @@ btr_cur_pessimistic_update(
ext_vect = mem_heap_alloc(heap, sizeof(ulint)
* dict_index_get_n_fields(index));
- ut_ad(!cursor->index->table->comp || !rec_get_node_ptr_flag(rec));
+ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
n_ext_vect = btr_push_update_extern_fields(ext_vect, offsets, update);
- if (rec_get_converted_size(index, new_entry) >=
- ut_min(page_get_free_space_of_empty(index->table->comp) / 2,
- REC_MAX_DATA_SIZE)) {
+ if (UNIV_UNLIKELY(rec_get_converted_size(index, new_entry) >=
+ ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2,
+ REC_MAX_DATA_SIZE))) {
big_rec_vec = dtuple_convert_big_rec(index, new_entry,
ext_vect, n_ext_vect);
@@ -1887,7 +1902,7 @@ btr_cur_pessimistic_update(
delete the lock structs set on the root page even if the root
page carries just node pointers. */
- lock_rec_store_on_page_infimum(rec);
+ lock_rec_store_on_page_infimum(buf_frame_align(rec), rec);
btr_search_update_hash_on_delete(cursor);
@@ -1965,8 +1980,7 @@ return_after_reservations:
mem_heap_free(heap);
if (n_extents > 0) {
- fil_space_release_free_extents(cursor->index->space,
- n_reserved);
+ fil_space_release_free_extents(index->space, n_reserved);
}
*big_rec = big_rec_vec;
@@ -1995,7 +2009,10 @@ btr_cur_del_mark_set_clust_rec_log(
ut_ad(flags < 256);
ut_ad(val <= 1);
- log_ptr = mlog_open_and_write_index(mtr, rec, index, index->table->comp
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
+
+ log_ptr = mlog_open_and_write_index(mtr, rec, index,
+ page_rec_is_comp(rec)
? MLOG_COMP_REC_CLUST_DELETE_MARK
: MLOG_REC_CLUST_DELETE_MARK,
1 + 1 + DATA_ROLL_PTR_LEN + 14 + 2);
@@ -2012,7 +2029,7 @@ btr_cur_del_mark_set_clust_rec_log(
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
mtr);
- mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
+ mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
log_ptr += 2;
mlog_close(mtr, log_ptr);
@@ -2032,13 +2049,15 @@ btr_cur_parse_del_mark_set_clust_rec(
page_t* page) /* in: page or NULL */
{
ulint flags;
- ibool val;
+ ulint val;
ulint pos;
dulint trx_id;
dulint roll_ptr;
ulint offset;
rec_t* rec;
+ ut_ad(!page || !!page_is_comp(page) == index->table->comp);
+
if (end_ptr < ptr + 2) {
return(NULL);
@@ -2078,7 +2097,7 @@ btr_cur_parse_del_mark_set_clust_rec(
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap),
pos, trx_id, roll_ptr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -2087,7 +2106,7 @@ btr_cur_parse_del_mark_set_clust_rec(
is only being recovered, and there cannot be a hash index to
it. */
- rec_set_deleted_flag(rec, index->table->comp, val);
+ rec_set_deleted_flag(rec, page_is_comp(page), val);
}
return(ptr);
@@ -2123,22 +2142,25 @@ btr_cur_del_mark_set_clust_rec(
rec = btr_cur_get_rec(cursor);
index = cursor->index;
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), index, "del mark ");
rec_print_new(stderr, rec, offsets);
}
+#endif /* UNIV_DEBUG */
ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_get_deleted_flag(rec, index->table->comp) == FALSE);
+ ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
err = lock_clust_rec_modify_check_and_lock(flags,
rec, index, offsets, thr);
if (err != DB_SUCCESS) {
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -2149,7 +2171,7 @@ btr_cur_del_mark_set_clust_rec(
&roll_ptr);
if (err != DB_SUCCESS) {
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -2161,7 +2183,7 @@ btr_cur_del_mark_set_clust_rec(
rw_lock_x_lock(&btr_search_latch);
}
- rec_set_deleted_flag(rec, index->table->comp, val);
+ rec_set_deleted_flag(rec, rec_offs_comp(offsets), val);
trx = thr_get_trx(thr);
@@ -2175,7 +2197,7 @@ btr_cur_del_mark_set_clust_rec(
btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx,
roll_ptr, mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(DB_SUCCESS);
@@ -2189,17 +2211,13 @@ void
btr_cur_del_mark_set_sec_rec_log(
/*=============================*/
rec_t* rec, /* in: record */
- dict_index_t* index, /* in: record descriptor */
ibool val, /* in: value to set */
mtr_t* mtr) /* in: mtr */
{
byte* log_ptr;
ut_ad(val <= 1);
- log_ptr = mlog_open_and_write_index(mtr, rec, index, index->table->comp
- ? MLOG_COMP_REC_SEC_DELETE_MARK
- : MLOG_REC_SEC_DELETE_MARK,
- 1 + 2);
+ log_ptr = mlog_open(mtr, 11 + 1 + 2);
if (!log_ptr) {
/* Logging in mtr is switched off during crash recovery:
@@ -2207,10 +2225,12 @@ btr_cur_del_mark_set_sec_rec_log(
return;
}
+ log_ptr = mlog_write_initial_log_record_fast(
+ rec, MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr);
mach_write_to_1(log_ptr, val);
log_ptr++;
- mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
+ mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
log_ptr += 2;
mlog_close(mtr, log_ptr);
@@ -2226,10 +2246,9 @@ btr_cur_parse_del_mark_set_sec_rec(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
page_t* page) /* in: page or NULL */
{
- ibool val;
+ ulint val;
ulint offset;
rec_t* rec;
@@ -2253,7 +2272,7 @@ btr_cur_parse_del_mark_set_sec_rec(
is only being recovered, and there cannot be a hash index to
it. */
- rec_set_deleted_flag(rec, index->table->comp, val);
+ rec_set_deleted_flag(rec, page_is_comp(page), val);
}
return(ptr);
@@ -2279,11 +2298,13 @@ btr_cur_del_mark_set_sec_rec(
rec = btr_cur_get_rec(cursor);
+#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), cursor->index,
"del mark ");
rec_print(stderr, rec, cursor->index);
}
+#endif /* UNIV_DEBUG */
err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index,
thr);
@@ -2293,18 +2314,21 @@ btr_cur_del_mark_set_sec_rec(
}
block = buf_block_align(rec);
+ ut_ad(!!page_is_comp(buf_block_get_frame(block))
+ == cursor->index->table->comp);
if (block->is_hashed) {
rw_lock_x_lock(&btr_search_latch);
}
- rec_set_deleted_flag(rec, cursor->index->table->comp, val);
+ rec_set_deleted_flag(rec, page_is_comp(buf_block_get_frame(block)),
+ val);
if (block->is_hashed) {
rw_lock_x_unlock(&btr_search_latch);
}
- btr_cur_del_mark_set_sec_rec_log(rec, cursor->index, val, mtr);
+ btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
return(DB_SUCCESS);
}
@@ -2317,15 +2341,14 @@ void
btr_cur_del_unmark_for_ibuf(
/*========================*/
rec_t* rec, /* in: record to delete unmark */
- dict_index_t* index, /* in: record descriptor */
mtr_t* mtr) /* in: mtr */
{
/* We do not need to reserve btr_search_latch, as the page has just
been read to the buffer pool and there cannot be a hash index to it. */
- rec_set_deleted_flag(rec, index->table->comp, FALSE);
+ rec_set_deleted_flag(rec, page_is_comp(buf_frame_align(rec)), FALSE);
- btr_cur_del_mark_set_sec_rec_log(rec, index, FALSE, mtr);
+ btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr);
}
/*==================== B-TREE RECORD REMOVE =========================*/
@@ -2444,7 +2467,7 @@ btr_cur_optimistic_delete(
mtr);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -2487,6 +2510,7 @@ btr_cur_pessimistic_delete(
ulint n_reserved;
ibool success;
ibool ret = FALSE;
+ ulint level;
mem_heap_t* heap;
ulint* offsets;
@@ -2523,15 +2547,15 @@ btr_cur_pessimistic_delete(
/* Free externally stored fields if the record is neither
a node pointer nor in two-byte format.
This avoids an unnecessary loop. */
- if (cursor->index->table->comp
+ if (page_is_comp(page)
? !rec_get_node_ptr_flag(rec)
: !rec_get_1byte_offs_flag(rec)) {
btr_rec_free_externally_stored_fields(cursor->index,
rec, offsets, in_rollback, mtr);
}
- if ((page_get_n_recs(page) < 2)
- && (dict_tree_get_page(btr_cur_get_tree(cursor))
+ if (UNIV_UNLIKELY(page_get_n_recs(page) < 2)
+ && UNIV_UNLIKELY(dict_tree_get_page(btr_cur_get_tree(cursor))
!= buf_frame_get_page_no(page))) {
/* If there is only one record, drop the whole page in
@@ -2546,9 +2570,13 @@ btr_cur_pessimistic_delete(
}
lock_update_delete(rec);
+ level = btr_page_get_level(page, mtr);
+
+ if (level > 0
+ && UNIV_UNLIKELY(rec == page_rec_get_next(
+ page_get_infimum_rec(page)))) {
- if ((btr_page_get_level(page, mtr) > 0)
- && (page_rec_get_next(page_get_infimum_rec(page)) == rec)) {
+ rec_t* next_rec = page_rec_get_next(rec);
if (btr_page_get_prev(page, mtr) == FIL_NULL) {
@@ -2556,8 +2584,8 @@ btr_cur_pessimistic_delete(
non-leaf level, we must mark the new leftmost node
pointer as the predefined minimum record */
- btr_set_min_rec_mark(page_rec_get_next(rec),
- cursor->index->table->comp, mtr);
+ btr_set_min_rec_mark(next_rec, page_is_comp(page),
+ mtr);
} else {
/* Otherwise, if we delete the leftmost node pointer
on a page, we have to change the father node pointer
@@ -2567,13 +2595,12 @@ btr_cur_pessimistic_delete(
btr_node_ptr_delete(tree, page, mtr);
node_ptr = dict_tree_build_node_ptr(
- tree, page_rec_get_next(rec),
+ tree, next_rec,
buf_frame_get_page_no(page),
- heap, btr_page_get_level(page, mtr));
+ heap, level);
btr_insert_on_non_leaf_level(tree,
- btr_page_get_level(page, mtr) + 1,
- node_ptr, mtr);
+ level + 1, node_ptr, mtr);
}
}
@@ -2813,24 +2840,24 @@ btr_estimate_number_of_different_key_vals(
ulint add_on;
mtr_t mtr;
mem_heap_t* heap = NULL;
- ulint offsets1_[REC_OFFS_NORMAL_SIZE];
- ulint offsets2_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets1 = offsets1_;
- ulint* offsets2 = offsets2_;
- *offsets1_ = (sizeof offsets1_) / sizeof *offsets1_;
- *offsets2_ = (sizeof offsets2_) / sizeof *offsets2_;
+ ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
+ ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets_rec = offsets_rec_;
+ ulint* offsets_next_rec= offsets_next_rec_;
+ *offsets_rec_ = (sizeof offsets_rec_) / sizeof *offsets_rec_;
+ *offsets_next_rec_ =
+ (sizeof offsets_next_rec_) / sizeof *offsets_next_rec_;
n_cols = dict_index_get_n_unique(index);
n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
- for (j = 0; j <= n_cols; j++) {
- n_diff[j] = 0;
- }
+ memset(n_diff, 0, (n_cols + 1) * sizeof(ib_longlong));
/* We sample some pages in the index to get an estimate */
for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) {
+ rec_t* supremum;
mtr_start(&mtr);
btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
@@ -2843,26 +2870,29 @@ btr_estimate_number_of_different_key_vals(
page = btr_cur_get_page(&cursor);
- rec = page_get_infimum_rec(page);
- rec = page_rec_get_next(rec);
+ supremum = page_get_supremum_rec(page);
+ rec = page_rec_get_next(page_get_infimum_rec(page));
- if (rec != page_get_supremum_rec(page)) {
+ if (rec != supremum) {
not_empty_flag = 1;
+ offsets_rec = rec_get_offsets(rec, index, offsets_rec,
+ ULINT_UNDEFINED, &heap);
}
-
- while (rec != page_get_supremum_rec(page)
- && page_rec_get_next(rec)
- != page_get_supremum_rec(page)) {
+
+ while (rec != supremum) {
rec_t* next_rec = page_rec_get_next(rec);
+ if (next_rec == supremum) {
+ break;
+ }
+
matched_fields = 0;
matched_bytes = 0;
- offsets1 = rec_get_offsets(rec, index, offsets1,
- ULINT_UNDEFINED, &heap);
- offsets2 = rec_get_offsets(next_rec, index, offsets2,
+ offsets_next_rec = rec_get_offsets(next_rec, index,
+ offsets_next_rec,
n_cols, &heap);
cmp_rec_rec_with_match(rec, next_rec,
- offsets1, offsets2,
+ offsets_rec, offsets_next_rec,
index, &matched_fields,
&matched_bytes);
@@ -2875,9 +2905,17 @@ btr_estimate_number_of_different_key_vals(
total_external_size +=
btr_rec_get_externally_stored_len(
- rec, offsets1);
+ rec, offsets_rec);
- rec = page_rec_get_next(rec);
+ rec = next_rec;
+ /* Initialize offsets_rec for the next round
+ and assign the old offsets_rec buffer to
+ offsets_next_rec. */
+ {
+ ulint* offsets_tmp = offsets_rec;
+ offsets_rec = offsets_next_rec;
+ offsets_next_rec = offsets_tmp;
+ }
}
@@ -2899,11 +2937,11 @@ btr_estimate_number_of_different_key_vals(
}
}
- offsets1 = rec_get_offsets(rec, index, offsets1,
+ offsets_rec = rec_get_offsets(rec, index, offsets_rec,
ULINT_UNDEFINED, &heap);
total_external_size +=
btr_rec_get_externally_stored_len(rec,
- offsets1);
+ offsets_rec);
mtr_commit(&mtr);
}
@@ -2944,7 +2982,7 @@ btr_estimate_number_of_different_key_vals(
}
mem_free(n_diff);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -3599,7 +3637,7 @@ btr_rec_free_externally_stored_fields(
MTR_MEMO_PAGE_X_FIX));
/* Free possible externally stored fields in the record */
- ut_ad(index->table->comp == rec_offs_comp(offsets));
+ ut_ad(index->table->comp == !!rec_offs_comp(offsets));
n_fields = rec_offs_n_fields(offsets);
for (i = 0; i < n_fields; i++) {
diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c
index 74feff8653c..cb398b4afab 100644
--- a/innobase/btr/btr0pcur.c
+++ b/innobase/btr/btr0pcur.c
@@ -78,6 +78,7 @@ btr_pcur_store_position(
rec_t* rec;
dict_tree_t* tree;
page_t* page;
+ ulint offs;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
@@ -87,7 +88,8 @@ btr_pcur_store_position(
page_cursor = btr_pcur_get_page_cur(cursor);
rec = page_cur_get_rec(page_cursor);
- page = buf_frame_align(rec);
+ page = ut_align_down(rec, UNIV_PAGE_SIZE);
+ offs = ut_align_offset(rec, UNIV_PAGE_SIZE);
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_S_FIX)
@@ -95,35 +97,33 @@ btr_pcur_store_position(
MTR_MEMO_PAGE_X_FIX));
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
- if (page_get_n_recs(page) == 0) {
+ if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
/* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
if we restore the cursor position */
- ut_a(btr_page_get_next(page, mtr) == FIL_NULL
- && btr_page_get_prev(page, mtr) == FIL_NULL);
+ ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
+ ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
- if (rec == page_get_supremum_rec(page)) {
+ cursor->old_stored = BTR_PCUR_OLD_STORED;
- cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
- cursor->old_stored = BTR_PCUR_OLD_STORED;
+ if (page_rec_is_supremum_low(offs)) {
- return;
+ cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
+ } else {
+ cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
}
- cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
- cursor->old_stored = BTR_PCUR_OLD_STORED;
-
return;
}
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum_low(offs)) {
rec = page_rec_get_prev(rec);
cursor->rel_pos = BTR_PCUR_AFTER;
- } else if (rec == page_get_infimum_rec(page)) {
+ } else if (page_rec_is_infimum_low(offs)) {
rec = page_rec_get_next(rec);
@@ -139,7 +139,8 @@ btr_pcur_store_position(
&cursor->buf_size);
cursor->block_when_stored = buf_block_align(page);
- cursor->modify_clock = buf_frame_get_modify_clock(page);
+ cursor->modify_clock = buf_block_get_modify_clock(
+ cursor->block_when_stored);
}
/******************************************************************
@@ -202,33 +203,27 @@ btr_pcur_restore_position(
dtuple_t* tuple;
ulint mode;
ulint old_mode;
- ibool from_left;
mem_heap_t* heap;
- ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
- || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
- if (cursor->old_stored != BTR_PCUR_OLD_STORED) {
+ if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
+ || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
+ && 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);
}
- ut_a(0);
+ ut_error;
}
- if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
- || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
+ if (UNIV_UNLIKELY(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
+ || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
/* In these cases we do not try an optimistic restoration,
but always do a search */
- if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
- from_left = TRUE;
- } else {
- from_left = FALSE;
- }
-
- btr_cur_open_at_index_side(from_left,
+ btr_cur_open_at_index_side(
+ cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
btr_pcur_get_btr_cur(cursor)->index, latch_mode,
btr_pcur_get_btr_cur(cursor), mtr);
@@ -243,12 +238,13 @@ btr_pcur_restore_position(
page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
- if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
+ if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
+ || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
/* Try optimistic restoration */
- if (buf_page_optimistic_get(latch_mode,
+ if (UNIV_LIKELY(buf_page_optimistic_get(latch_mode,
cursor->block_when_stored, page,
- cursor->modify_clock, mtr)) {
+ cursor->modify_clock, mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
#ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(page, SYNC_TREE_NODE);
@@ -297,7 +293,7 @@ btr_pcur_restore_position(
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
- if (cursor->rel_pos == BTR_PCUR_ON) {
+ if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
mode = PAGE_CUR_LE;
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
mode = PAGE_CUR_G;
@@ -323,12 +319,10 @@ btr_pcur_restore_position(
the cursor can now be on a different page! But we can retain
the value of old_rec */
- cursor->modify_clock =
- buf_frame_get_modify_clock(btr_pcur_get_page(cursor));
-
cursor->block_when_stored =
buf_block_align(btr_pcur_get_page(cursor));
-
+ cursor->modify_clock =
+ buf_block_get_modify_clock(cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index 97fdce2df75..f705fee4275 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -435,7 +435,7 @@ btr_search_update_hash_ref(
offsets_, ULINT_UNDEFINED, &heap),
block->curr_n_fields,
block->curr_n_bytes, tree_id);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
#ifdef UNIV_SYNC_DEBUG
@@ -544,10 +544,7 @@ btr_search_check_guess(
or PAGE_CUR_GE */
mtr_t* mtr) /* in: mtr */
{
- page_t* page;
rec_t* rec;
- rec_t* prev_rec;
- rec_t* next_rec;
ulint n_unique;
ulint match;
ulint bytes;
@@ -561,7 +558,6 @@ btr_search_check_guess(
n_unique = dict_index_get_n_unique_in_tree(cursor->index);
rec = btr_cur_get_rec(cursor);
- page = buf_frame_align(rec);
ut_ad(page_rec_is_user_rec(rec));
@@ -611,13 +607,16 @@ btr_search_check_guess(
bytes = 0;
if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)) {
+ rec_t* prev_rec;
- ut_ad(rec != page_get_infimum_rec(page));
+ ut_ad(!page_rec_is_infimum(rec));
prev_rec = page_rec_get_prev(rec);
- if (prev_rec == page_get_infimum_rec(page)) {
- success = btr_page_get_prev(page, mtr) == FIL_NULL;
+ if (page_rec_is_infimum(prev_rec)) {
+ success = btr_page_get_prev(
+ buf_frame_align(prev_rec), mtr) == FIL_NULL;
+
goto exit_func;
}
@@ -632,34 +631,37 @@ btr_search_check_guess(
}
goto exit_func;
- }
-
- ut_ad(rec != page_get_supremum_rec(page));
+ } else {
+ rec_t* next_rec;
+
+ ut_ad(!page_rec_is_supremum(rec));
- next_rec = page_rec_get_next(rec);
+ next_rec = page_rec_get_next(rec);
- if (next_rec == page_get_supremum_rec(page)) {
- if (btr_page_get_next(page, mtr) == FIL_NULL) {
+ if (page_rec_is_supremum(next_rec)) {
+ if (btr_page_get_next(
+ buf_frame_align(next_rec), mtr) == FIL_NULL) {
- cursor->up_match = 0;
- success = TRUE;
- }
+ cursor->up_match = 0;
+ success = TRUE;
+ }
- goto exit_func;
- }
+ goto exit_func;
+ }
- offsets = rec_get_offsets(next_rec, cursor->index, offsets,
+ offsets = rec_get_offsets(next_rec, cursor->index, offsets,
n_unique, &heap);
- cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec,
- offsets, &match, &bytes);
- if (mode == PAGE_CUR_LE) {
- success = cmp == -1;
- cursor->up_match = match;
- } else {
- success = cmp != 1;
+ cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec,
+ offsets, &match, &bytes);
+ if (mode == PAGE_CUR_LE) {
+ success = cmp == -1;
+ cursor->up_match = match;
+ } else {
+ success = cmp != 1;
+ }
}
exit_func:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(success);
@@ -694,7 +696,6 @@ btr_search_guess_on_hash(
buf_block_t* block;
rec_t* rec;
page_t* page;
- ibool success;
ulint fold;
ulint tuple_n_fields;
dulint tree_id;
@@ -710,7 +711,7 @@ btr_search_guess_on_hash(
/* Note that, for efficiency, the struct info may not be protected by
any latch here! */
- if (info->n_hash_potential == 0) {
+ if (UNIV_UNLIKELY(info->n_hash_potential == 0)) {
return(FALSE);
}
@@ -720,12 +721,13 @@ btr_search_guess_on_hash(
tuple_n_fields = dtuple_get_n_fields(tuple);
- if (tuple_n_fields < cursor->n_fields) {
+ if (UNIV_UNLIKELY(tuple_n_fields < cursor->n_fields)) {
return(FALSE);
}
- if ((cursor->n_bytes > 0) && (tuple_n_fields <= cursor->n_fields)) {
+ if (UNIV_UNLIKELY(tuple_n_fields == cursor->n_fields)
+ && (cursor->n_bytes > 0)) {
return(FALSE);
}
@@ -740,39 +742,31 @@ btr_search_guess_on_hash(
cursor->fold = fold;
cursor->flag = BTR_CUR_HASH;
- if (!has_search_latch) {
+ if (UNIV_LIKELY(!has_search_latch)) {
rw_lock_s_lock(&btr_search_latch);
}
- ut_a(btr_search_latch.writer != RW_LOCK_EX);
- ut_a(btr_search_latch.reader_count > 0);
+ ut_ad(btr_search_latch.writer != RW_LOCK_EX);
+ ut_ad(btr_search_latch.reader_count > 0);
rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
- if (!rec) {
- if (!has_search_latch) {
- rw_lock_s_unlock(&btr_search_latch);
- }
-
- goto failure;
+ if (UNIV_UNLIKELY(!rec)) {
+ goto failure_unlock;
}
page = buf_frame_align(rec);
- if (!has_search_latch) {
+ if (UNIV_LIKELY(!has_search_latch)) {
- success = buf_page_get_known_nowait(latch_mode, page,
+ if (UNIV_UNLIKELY(!buf_page_get_known_nowait(latch_mode, page,
BUF_MAKE_YOUNG,
__FILE__, __LINE__,
- mtr);
-
- rw_lock_s_unlock(&btr_search_latch);
-
- if (!success) {
-
- goto failure;
+ mtr))) {
+ goto failure_unlock;
}
+ rw_lock_s_unlock(&btr_search_latch);
can_only_compare_to_cursor_rec = FALSE;
#ifdef UNIV_SYNC_DEBUG
@@ -782,8 +776,8 @@ btr_search_guess_on_hash(
block = buf_block_align(page);
- if (block->state == BUF_BLOCK_REMOVE_HASH) {
- if (!has_search_latch) {
+ if (UNIV_UNLIKELY(block->state == BUF_BLOCK_REMOVE_HASH)) {
+ if (UNIV_LIKELY(!has_search_latch)) {
btr_leaf_page_release(page, latch_mode, mtr);
}
@@ -791,51 +785,33 @@ btr_search_guess_on_hash(
goto failure;
}
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(page_rec_is_user_rec(rec));
+ ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_ad(page_rec_is_user_rec(rec));
btr_cur_position(index, rec, cursor);
/* Check the validity of the guess within the page */
- if (0 != ut_dulint_cmp(tree_id, btr_page_get_index_id(page))) {
-
- success = FALSE;
-/*
- fprintf(stderr, "Tree id %lu, page index id %lu fold %lu\n",
- ut_dulint_get_low(tree_id),
- ut_dulint_get_low(btr_page_get_index_id(page)),
- fold);
-*/
- } else {
- /* If we only have the latch on btr_search_latch, not on the
- page, it only protects the columns of the record the cursor
- is positioned on. We cannot look at the next of the previous
- record to determine if our guess for the cursor position is
- right. */
-
- success = btr_search_check_guess(cursor,
- can_only_compare_to_cursor_rec,
- tuple, mode, mtr);
- }
-
- if (!success) {
- if (!has_search_latch) {
+ /* If we only have the latch on btr_search_latch, not on the
+ page, it only protects the columns of the record the cursor
+ is positioned on. We cannot look at the next of the previous
+ record to determine if our guess for the cursor position is
+ right. */
+ if (UNIV_EXPECT(ut_dulint_cmp(tree_id, btr_page_get_index_id(page)), 0)
+ || !btr_search_check_guess(cursor, can_only_compare_to_cursor_rec,
+ tuple, mode, mtr)) {
+ if (UNIV_LIKELY(!has_search_latch)) {
btr_leaf_page_release(page, latch_mode, mtr);
}
goto failure;
}
- if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) {
+ if (UNIV_LIKELY(info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5)) {
info->n_hash_potential++;
}
- if (info->last_hash_succ != TRUE) {
- info->last_hash_succ = TRUE;
- }
-
#ifdef notdefined
/* These lines of code can be used in a debug version to check
the correctness of the searched cursor position: */
@@ -843,15 +819,14 @@ btr_search_guess_on_hash(
info->last_hash_succ = FALSE;
/* Currently, does not work if the following fails: */
- ut_a(!has_search_latch);
+ ut_ad(!has_search_latch);
btr_leaf_page_release(page, latch_mode, mtr);
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
&cursor2, 0, mtr);
if (mode == PAGE_CUR_GE
- && btr_cur_get_rec(&cursor2) == page_get_supremum_rec(
- buf_frame_align(btr_cur_get_rec(&cursor2)))) {
+ && page_rec_is_supremum(btr_cur_get_rec(&cursor2))) {
/* If mode is PAGE_CUR_GE, then the binary search
in the index tree may actually take us to the supremum
@@ -861,22 +836,22 @@ btr_search_guess_on_hash(
btr_pcur_open_on_user_rec(index, tuple, mode, latch_mode,
&pcur, mtr);
- ut_a(btr_pcur_get_rec(&pcur) == btr_cur_get_rec(cursor));
+ ut_ad(btr_pcur_get_rec(&pcur) == btr_cur_get_rec(cursor));
} else {
- ut_a(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor));
+ ut_ad(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor));
}
/* NOTE that it is theoretically possible that the above assertions
fail if the page of the cursor gets removed from the buffer pool
meanwhile! Thus it might not be a bug. */
-
- info->last_hash_succ = TRUE;
#endif
+ info->last_hash_succ = TRUE;
#ifdef UNIV_SEARCH_PERF_STAT
btr_search_n_succ++;
#endif
- if (!has_search_latch && buf_block_peek_if_too_old(block)) {
+ if (UNIV_LIKELY(!has_search_latch)
+ && buf_block_peek_if_too_old(block)) {
buf_page_make_young(page);
}
@@ -889,6 +864,10 @@ btr_search_guess_on_hash(
return(TRUE);
/*-------------------------------------------*/
+failure_unlock:
+ if (UNIV_LIKELY(!has_search_latch)) {
+ rw_lock_s_unlock(&btr_search_latch);
+ }
failure:
info->n_hash_fail++;
@@ -917,7 +896,6 @@ btr_search_drop_page_hash_index(
ulint n_fields;
ulint n_bytes;
rec_t* rec;
- rec_t* sup;
ulint fold;
ulint prev_fold;
dulint tree_id;
@@ -968,12 +946,10 @@ btr_search_drop_page_hash_index(
n_cached = 0;
- sup = page_get_supremum_rec(page);
-
rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec);
- if (rec != sup) {
+ if (!page_rec_is_supremum(rec)) {
ut_a(n_fields <= rec_get_n_fields(rec, block->index));
if (n_bytes > 0) {
@@ -988,7 +964,7 @@ btr_search_drop_page_hash_index(
heap = NULL;
offsets = NULL;
- while (rec != sup) {
+ while (!page_rec_is_supremum(rec)) {
/* FIXME: in a mixed tree, not all records may have enough
ordering fields: */
offsets = rec_get_offsets(rec, block->index,
@@ -1010,7 +986,7 @@ next_rec:
prev_fold = fold;
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -1090,7 +1066,6 @@ btr_search_build_page_hash_index(
buf_block_t* block;
rec_t* rec;
rec_t* next_rec;
- rec_t* sup;
ulint fold;
ulint next_fold;
dulint tree_id;
@@ -1158,15 +1133,13 @@ btr_search_build_page_hash_index(
tree_id = btr_page_get_index_id(page);
- sup = page_get_supremum_rec(page);
-
rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec);
offsets = rec_get_offsets(rec, index, offsets,
n_fields + (n_bytes > 0), &heap);
- if (rec != sup) {
+ if (!page_rec_is_supremum(rec)) {
ut_a(n_fields <= rec_offs_n_fields(offsets));
if (n_bytes > 0) {
@@ -1188,7 +1161,7 @@ btr_search_build_page_hash_index(
for (;;) {
next_rec = page_rec_get_next(rec);
- if (next_rec == sup) {
+ if (page_rec_is_supremum(next_rec)) {
if (side == BTR_SEARCH_RIGHT_SIDE) {
@@ -1252,7 +1225,7 @@ exit_func:
mem_free(folds);
mem_free(recs);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -1370,7 +1343,7 @@ btr_search_update_hash_on_delete(
fold = rec_fold(rec, rec_get_offsets(rec, cursor->index, offsets_,
ULINT_UNDEFINED, &heap), block->curr_n_fields,
block->curr_n_bytes, tree_id);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
rw_lock_x_lock(&btr_search_latch);
@@ -1443,7 +1416,6 @@ btr_search_update_hash_on_insert(
{
hash_table_t* table;
buf_block_t* block;
- page_t* page;
rec_t* rec;
rec_t* ins_rec;
rec_t* next_rec;
@@ -1488,19 +1460,18 @@ btr_search_update_hash_on_insert(
ins_rec = page_rec_get_next(rec);
next_rec = page_rec_get_next(ins_rec);
- page = buf_frame_align(rec);
offsets = rec_get_offsets(ins_rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, tree_id);
- if (next_rec != page_get_supremum_rec(page)) {
+ if (!page_rec_is_supremum(next_rec)) {
offsets = rec_get_offsets(next_rec, cursor->index, offsets,
n_fields + (n_bytes > 0), &heap);
next_fold = rec_fold(next_rec, offsets, n_fields,
n_bytes, tree_id);
}
- if (rec != page_get_infimum_rec(page)) {
+ if (!page_rec_is_infimum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets,
n_fields + (n_bytes > 0), &heap);
fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);
@@ -1534,7 +1505,7 @@ btr_search_update_hash_on_insert(
}
check_next_rec:
- if (next_rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(next_rec)) {
if (side == BTR_SEARCH_RIGHT_SIDE) {
@@ -1573,7 +1544,7 @@ check_next_rec:
}
function_exit:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
if (locked) {
@@ -1662,7 +1633,7 @@ btr_search_validate(void)
}
rw_lock_x_unlock(&btr_search_latch);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index 89f851709db..fe4498e6f10 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -223,13 +223,14 @@ in the free list to the frames.
buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */
+#ifdef UNIV_DEBUG
ulint buf_dbg_counter = 0; /* This is used to insert validation
operations in excution in the
debug version */
ibool buf_debug_prints = FALSE; /* If this is set TRUE,
the program prints info whenever
read-ahead or flush occurs */
-
+#endif /* UNIV_DEBUG */
/************************************************************************
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
@@ -1286,8 +1287,9 @@ buf_page_optimistic_get_func(
/* If AWE is used, block may have a different frame now, e.g., NULL */
- if (block->state != BUF_BLOCK_FILE_PAGE || block->frame != guess) {
-
+ if (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
+ || UNIV_UNLIKELY(block->frame != guess)) {
+ exit_func:
mutex_exit(&(buf_pool->mutex));
return(FALSE);
@@ -1320,19 +1322,17 @@ buf_page_optimistic_get_func(
fix_type = MTR_MEMO_PAGE_X_FIX;
}
- if (!success) {
+ if (UNIV_UNLIKELY(!success)) {
mutex_enter(&(buf_pool->mutex));
block->buf_fix_count--;
#ifdef UNIV_SYNC_DEBUG
rw_lock_s_unlock(&(block->debug_latch));
-#endif
- mutex_exit(&(buf_pool->mutex));
-
- return(FALSE);
+#endif
+ goto exit_func;
}
- if (!UT_DULINT_EQ(modify_clock, block->modify_clock)) {
+ if (UNIV_UNLIKELY(!UT_DULINT_EQ(modify_clock, block->modify_clock))) {
#ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(block->frame, SYNC_NO_ORDER_CHECK);
#endif /* UNIV_SYNC_DEBUG */
@@ -1347,10 +1347,8 @@ buf_page_optimistic_get_func(
block->buf_fix_count--;
#ifdef UNIV_SYNC_DEBUG
rw_lock_s_unlock(&(block->debug_latch));
-#endif
- mutex_exit(&(buf_pool->mutex));
-
- return(FALSE);
+#endif
+ goto exit_func;
}
mtr_memo_push(mtr, block, fix_type);
@@ -1368,7 +1366,7 @@ buf_page_optimistic_get_func(
#ifdef UNIV_DEBUG_FILE_ACCESSES
ut_a(block->file_page_was_freed == FALSE);
#endif
- if (!accessed) {
+ if (UNIV_UNLIKELY(!accessed)) {
/* In the case of a first access, try to apply linear
read-ahead */
@@ -1742,10 +1740,12 @@ buf_page_create(
/* If we get here, the page was not in buf_pool: init it there */
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr, "Creating space %lu page %lu to buffer\n",
(ulong) space, (ulong) offset);
}
+#endif /* UNIV_DEBUG */
block = free_block;
@@ -1896,9 +1896,11 @@ buf_page_io_complete(
rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fputs("Has read ", stderr);
}
+#endif /* UNIV_DEBUG */
} else {
ut_ad(io_type == BUF_IO_WRITE);
@@ -1911,17 +1913,21 @@ buf_page_io_complete(
buf_pool->n_pages_written++;
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fputs("Has written ", stderr);
}
+#endif /* UNIV_DEBUG */
}
mutex_exit(&(buf_pool->mutex));
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr, "page space %lu page no %lu\n",
(ulong) block->space, (ulong) block->offset);
}
+#endif /* UNIV_DEBUG */
}
/*************************************************************************
@@ -1950,6 +1956,7 @@ buf_pool_invalidate(void)
mutex_exit(&(buf_pool->mutex));
}
+#ifdef UNIV_DEBUG
/*************************************************************************
Validates the buffer buf_pool data structure. */
@@ -2094,10 +2101,6 @@ buf_print(void)
n_found = 0;
- for (i = 0 ; i < size; i++) {
- counts[i] = 0;
- }
-
for (i = 0; i < size; i++) {
frame = buf_pool_get_nth_block(buf_pool, i)->frame;
@@ -2149,6 +2152,7 @@ buf_print(void)
ut_a(buf_validate());
}
+#endif /* UNIV_DEBUG */
/*************************************************************************
Returns the number of latched pages in the buffer pool. */
diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c
index 592ed972376..ffb16790b2d 100644
--- a/innobase/buf/buf0flu.c
+++ b/innobase/buf/buf0flu.c
@@ -586,11 +586,13 @@ buf_flush_try_page(
rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
}
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Flushing page space %lu, page no %lu \n",
(ulong) block->space, (ulong) block->offset);
}
+#endif /* UNIV_DEBUG */
buf_flush_write_block_low(block);
@@ -674,12 +676,14 @@ buf_flush_try_page(
rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Flushing single page space %lu, page no %lu \n",
(ulong) block->space,
(ulong) block->offset);
}
+#endif /* UNIV_DEBUG */
buf_flush_write_block_low(block);
@@ -906,6 +910,7 @@ buf_flush_batch(
buf_flush_buffered_writes();
+#ifdef UNIV_DEBUG
if (buf_debug_prints && page_count > 0) {
ut_a(flush_type == BUF_FLUSH_LRU
|| flush_type == BUF_FLUSH_LIST);
@@ -914,6 +919,7 @@ buf_flush_batch(
: "Flushed %lu pages in flush list flush\n",
(ulong) page_count);
}
+#endif /* UNIV_DEBUG */
if (page_count != ULINT_UNDEFINED)
srv_buf_pool_flushed+= page_count;
diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c
index 18c4f8c10fb..a0157da2d42 100644
--- a/innobase/buf/buf0lru.c
+++ b/innobase/buf/buf0lru.c
@@ -213,12 +213,14 @@ buf_LRU_search_and_free_block(
ut_a(block->in_LRU_list);
if (buf_flush_ready_for_replace(block)) {
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Putting space %lu page %lu to free list\n",
(ulong) block->space,
(ulong) block->offset);
}
+#endif /* UNIV_DEBUG */
buf_LRU_block_remove_hashed_page(block);
@@ -919,7 +921,8 @@ buf_LRU_block_free_hashed_page(
buf_LRU_block_free_non_file_page(block);
}
-
+
+#ifdef UNIV_DEBUG
/**************************************************************************
Validates the LRU list. */
@@ -1050,3 +1053,4 @@ buf_LRU_print(void)
mutex_exit(&(buf_pool->mutex));
}
+#endif /* UNIV_DEBUG */
diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c
index d9dc2ca93f5..813ca589907 100644
--- a/innobase/buf/buf0rea.c
+++ b/innobase/buf/buf0rea.c
@@ -288,12 +288,14 @@ buf_read_ahead_random(
os_aio_simulated_wake_handler_threads();
+#ifdef UNIV_DEBUG
if (buf_debug_prints && (count > 0)) {
fprintf(stderr,
"Random read-ahead space %lu offset %lu pages %lu\n",
(ulong) space, (ulong) offset,
(ulong) count);
}
+#endif /* UNIV_DEBUG */
++srv_read_ahead_rnd;
return(count);
@@ -575,11 +577,13 @@ buf_read_ahead_linear(
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
+#ifdef UNIV_DEBUG
if (buf_debug_prints && (count > 0)) {
fprintf(stderr,
"LINEAR read-ahead space %lu offset %lu pages %lu\n",
(ulong) space, (ulong) offset, (ulong) count);
}
+#endif /* UNIV_DEBUG */
++srv_read_ahead_seq;
return(count);
@@ -641,11 +645,13 @@ buf_read_ibuf_merge_pages(
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Ibuf merge read-ahead space %lu pages %lu\n",
(ulong) space_ids[0], (ulong) n_stored);
}
+#endif /* UNIV_DEBUG */
}
/************************************************************************
@@ -711,8 +717,10 @@ buf_read_recv_pages(
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
+#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Recovery applies read-ahead pages %lu\n", (ulong) n_stored);
}
+#endif /* UNIV_DEBUG */
}
diff --git a/innobase/configure.in b/innobase/configure.in
index baf11272ab9..c56bd8274c4 100644
--- a/innobase/configure.in
+++ b/innobase/configure.in
@@ -117,6 +117,13 @@ case "$target" in
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
esac
+# must go in pair with AR as set by MYSQL_CHECK_AR
+if test -z "$ARFLAGS"
+then
+ ARFLAGS="cru"
+fi
+AC_SUBST(ARFLAGS)
+
AC_OUTPUT(Makefile os/Makefile ut/Makefile btr/Makefile dnl
buf/Makefile data/Makefile dnl
dict/Makefile dyn/Makefile dnl
diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c
index 5f74dde8710..194213a04e1 100644
--- a/innobase/data/data0data.c
+++ b/innobase/data/data0data.c
@@ -502,7 +502,7 @@ dtuple_convert_big_rec(
size = rec_get_converted_size(index, entry);
- if (size > 1000000000) {
+ if (UNIV_UNLIKELY(size > 1000000000)) {
fprintf(stderr,
"InnoDB: Warning: tuple size very big: %lu\n", (ulong) size);
fputs("InnoDB: Tuple contents: ", stderr);
diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c
index 3fcd666b5a5..d4264ad2926 100644
--- a/innobase/data/data0type.c
+++ b/innobase/data/data0type.c
@@ -39,7 +39,6 @@ column definitions, or records in the insert buffer, we use this
charset-collation code for them. */
ulint data_mysql_default_charset_coll = 99999999;
-ulint data_mysql_latin1_swedish_charset_coll = 99999999;
dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0, 0};
dtype_t* dtype_binary = &dtype_binary_val;
@@ -64,9 +63,10 @@ dtype_get_at_most_n_mbchars(
{
#ifndef UNIV_HOTBACKUP
ut_a(data_len != UNIV_SQL_NULL);
- ut_a(!(prefix_len % dtype->mbmaxlen));
+ ut_ad(!dtype->mbmaxlen || !(prefix_len % dtype->mbmaxlen));
if (dtype->mbminlen != dtype->mbmaxlen) {
+ ut_a(!(prefix_len % dtype->mbmaxlen));
return(innobase_get_at_most_n_mbchars(
dtype_get_charset_coll(dtype->prtype),
prefix_len, data_len, str));
diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c
index 0f6d55c9341..18a707a1b93 100644
--- a/innobase/dict/dict0boot.c
+++ b/innobase/dict/dict0boot.c
@@ -66,15 +66,6 @@ dict_hdr_get_new_id(
dict_hdr = dict_hdr_get(&mtr);
id = mtr_read_dulint(dict_hdr + type, &mtr);
-
- /* Add some dummy code here because otherwise pgcc seems to
- compile wrong */
-
- if (0 == ut_dulint_cmp(id, ut_dulint_max)) {
- /* TO DO: remove this code, or make it conditional */
- ut_dbg_null_ptr = 0;
- }
-
id = ut_dulint_add(id, 1);
mlog_write_dulint(dict_hdr + type, id, &mtr);
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 1f12386e413..c7d6ffd2c22 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -736,7 +736,7 @@ dict_truncate_index_tree(
dulint index_id;
byte* ptr;
ulint len;
- ibool comp;
+ ulint comp;
dict_index_t* index;
#ifdef UNIV_SYNC_DEBUG
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 0c39defeada..9580a80e7e7 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -1453,7 +1453,7 @@ dict_index_add_to_cache(
/* Increment the ord_part counts in columns which are ordering */
- if (index->type & DICT_UNIVERSAL) {
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
n_ord = new_index->n_fields;
} else {
n_ord = dict_index_get_n_unique(new_index);
@@ -1482,7 +1482,7 @@ dict_index_add_to_cache(
new_index->tree = tree;
}
- if (!(new_index->type & DICT_UNIVERSAL)) {
+ if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
new_index->stat_n_diff_key_vals =
mem_heap_alloc(new_index->heap,
@@ -1683,7 +1683,7 @@ dict_index_copy_types(
dtype_t* type;
ulint i;
- if (index->type & DICT_UNIVERSAL) {
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
dtuple_set_types_binary(tuple, n_fields);
return;
@@ -1779,7 +1779,7 @@ dict_index_build_internal_clust(
dict_index_copy(new_index, index, 0, index->n_fields);
}
- if (index->type & DICT_UNIVERSAL) {
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
/* No fixed number of fields determines an entry uniquely */
new_index->n_uniq = ULINT_MAX;
@@ -3682,7 +3682,7 @@ dict_tree_find_index_low(
table = index->table;
if ((index->type & DICT_CLUSTERED)
- && (table->type != DICT_TABLE_ORDINARY)) {
+ && UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) {
/* Get the mix id of the record */
ut_a(!table->comp);
@@ -3838,7 +3838,7 @@ dict_tree_build_node_ptr(
ind = dict_tree_find_index_low(tree, rec);
- if (tree->type & DICT_UNIVERSAL) {
+ if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
/* In a universal index tree, we take the whole record as
the node pointer if the reord is on the leaf level,
on non-leaf levels we remove the last field, which
@@ -3903,9 +3903,10 @@ dict_tree_copy_rec_order_prefix(
dict_index_t* index;
ulint n;
+ UNIV_PREFETCH_R(rec);
index = dict_tree_find_index_low(tree, rec);
- if (tree->type & DICT_UNIVERSAL) {
+ if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
ut_a(!index->table->comp);
n = rec_get_n_fields_old(rec);
} else {
@@ -3957,7 +3958,7 @@ dict_index_calc_min_rec_len(
ulint sum = 0;
ulint i;
- if (index->table->comp) {
+ if (UNIV_LIKELY(index->table->comp)) {
ulint nullable = 0;
sum = REC_N_NEW_EXTRA_BYTES;
for (i = 0; i < dict_index_get_n_fields(index); i++) {
@@ -4277,9 +4278,11 @@ dict_index_print_low(
putc('\n', stderr);
-/* btr_print_size(tree); */
+#ifdef UNIV_BTR_PRINT
+ btr_print_size(tree);
-/* btr_print_tree(tree, 7); */
+ btr_print_tree(tree, 7);
+#endif /* UNIV_BTR_PRINT */
}
/**************************************************************************
diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c
index 48b9f28d292..eec35310039 100644
--- a/innobase/dict/dict0mem.c
+++ b/innobase/dict/dict0mem.c
@@ -42,6 +42,7 @@ dict_mem_table_create(
mem_heap_t* heap;
ut_ad(name);
+ ut_ad(comp == FALSE || comp == TRUE);
heap = mem_heap_create(DICT_HEAP_SIZE);
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index 8600f583dbd..20f522c1a60 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -99,7 +99,6 @@ ulint fil_n_pending_tablespace_flushes = 0;
fil_addr_t fil_addr_null = {FIL_NULL, 0};
/* File node of a tablespace or the log data space */
-typedef struct fil_node_struct fil_node_t;
struct fil_node_struct {
fil_space_t* space; /* backpointer to the space where this node
belongs */
@@ -3411,9 +3410,9 @@ fil_extend_space_to_desired_size(
fil_space_t* space;
byte* buf2;
byte* buf;
+ ulint buf_size;
ulint start_page_no;
ulint file_start_page_no;
- ulint n_pages;
ulint offset_high;
ulint offset_low;
ibool success = TRUE;
@@ -3438,22 +3437,20 @@ fil_extend_space_to_desired_size(
fil_node_prepare_for_io(node, system, space);
- /* Extend 1 MB at a time */
-
- buf2 = mem_alloc(1024 * 1024 + UNIV_PAGE_SIZE);
- buf = ut_align(buf2, UNIV_PAGE_SIZE);
-
- memset(buf, '\0', 1024 * 1024);
-
start_page_no = space->size;
file_start_page_no = space->size - node->size;
- while (start_page_no < size_after_extend) {
- n_pages = size_after_extend - start_page_no;
+ /* Extend at most 64 pages at a time */
+ buf_size = ut_min(64, size_after_extend - start_page_no)
+ * UNIV_PAGE_SIZE;
+ buf2 = mem_alloc(buf_size + UNIV_PAGE_SIZE);
+ buf = ut_align(buf2, UNIV_PAGE_SIZE);
- if (n_pages > (1024 * 1024) / UNIV_PAGE_SIZE) {
- n_pages = (1024 * 1024) / UNIV_PAGE_SIZE;
- }
+ memset(buf, 0, buf_size);
+
+ while (start_page_no < size_after_extend) {
+ ulint n_pages = ut_min(buf_size / UNIV_PAGE_SIZE,
+ size_after_extend - start_page_no);
offset_high = (start_page_no - file_start_page_no)
/ (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE));
@@ -4035,7 +4032,7 @@ fil_aio_wait(
if (os_aio_use_native_aio) {
srv_set_io_thread_op_info(segment, "native aio handle");
#ifdef WIN_ASYNC_IO
- ret = os_aio_windows_handle(segment, 0, (void**) &fil_node,
+ ret = os_aio_windows_handle(segment, 0, &fil_node,
&message, &type);
#elif defined(POSIX_ASYNC_IO)
ret = os_aio_posix_handle(segment, &fil_node, &message);
@@ -4046,7 +4043,7 @@ fil_aio_wait(
} else {
srv_set_io_thread_op_info(segment, "simulated aio handle");
- ret = os_aio_simulated_handle(segment, (void**) &fil_node,
+ ret = os_aio_simulated_handle(segment, &fil_node,
&message, &type);
}
diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c
index ef8e70646c6..ad4228f6797 100644
--- a/innobase/fsp/fsp0fsp.c
+++ b/innobase/fsp/fsp0fsp.c
@@ -2325,7 +2325,6 @@ fseg_alloc_free_page_low(
dulint seg_id;
ulint used;
ulint reserved;
- fil_addr_t first;
xdes_t* descr; /* extent of the hinted page */
ulint ret_page; /* the allocated page offset, FIL_NULL
if could not be allocated */
@@ -2428,6 +2427,8 @@ fseg_alloc_free_page_low(
} else if (reserved - used > 0) {
/* 5. We take any unused page from the segment
==============================================*/
+ fil_addr_t first;
+
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
mtr);
@@ -2435,6 +2436,7 @@ fseg_alloc_free_page_low(
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
} else {
ut_error;
+ return(FIL_NULL);
}
ret_descr = xdes_lst_get_descriptor(space, first, mtr);
diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c
index 5ad61e2590f..d7fa48b6e66 100644
--- a/innobase/ibuf/ibuf0ibuf.c
+++ b/innobase/ibuf/ibuf0ibuf.c
@@ -1889,7 +1889,7 @@ ibuf_get_merge_page_nos(
contract the tree, FALSE if this is called
when a single page becomes full and we look
if it pays to read also nearby pages */
- rec_t* first_rec,/* in: record from which we read up and down
+ rec_t* rec, /* in: record from which we read up and down
in the chain of records */
ulint* space_ids,/* in/out: space id's of the pages */
ib_longlong* space_versions,/* in/out: tablespace version
@@ -1907,47 +1907,42 @@ ibuf_get_merge_page_nos(
ulint first_space_id;
ulint rec_page_no;
ulint rec_space_id;
- rec_t* rec;
ulint sum_volumes;
ulint volume_for_page;
ulint rec_volume;
ulint limit;
- page_t* page;
ulint n_pages;
*n_stored = 0;
limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
- page = buf_frame_align(first_rec);
-
- if (first_rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
- first_rec = page_rec_get_prev(first_rec);
+ rec = page_rec_get_prev(rec);
}
- if (first_rec == page_get_infimum_rec(page)) {
+ if (page_rec_is_infimum(rec)) {
- first_rec = page_rec_get_next(first_rec);
+ rec = page_rec_get_next(rec);
}
- if (first_rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
return(0);
}
- rec = first_rec;
- first_page_no = ibuf_rec_get_page_no(first_rec);
- first_space_id = ibuf_rec_get_space(first_rec);
+ first_page_no = ibuf_rec_get_page_no(rec);
+ first_space_id = ibuf_rec_get_space(rec);
n_pages = 0;
prev_page_no = 0;
prev_space_id = 0;
- /* Go backwards from the first_rec until we reach the border of the
+ /* Go backwards from the first rec until we reach the border of the
'merge area', or the page start or the limit of storeable pages is
reached */
- while ((rec != page_get_infimum_rec(page)) && (n_pages < limit)) {
+ while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
rec_page_no = ibuf_rec_get_page_no(rec);
rec_space_id = ibuf_rec_get_space(rec);
@@ -1982,7 +1977,7 @@ ibuf_get_merge_page_nos(
volume_for_page = 0;
while (*n_stored < limit) {
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
/* When no more records available, mark this with
another 'impossible' pair of space id, page no */
rec_page_no = 1;
@@ -2311,12 +2306,12 @@ ibuf_get_volume_buffered(
page = buf_frame_align(rec);
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
rec = page_rec_get_prev(rec);
}
for (;;) {
- if (rec == page_get_infimum_rec(page)) {
+ if (page_rec_is_infimum(rec)) {
break;
}
@@ -2351,7 +2346,7 @@ ibuf_get_volume_buffered(
rec = page_rec_get_prev(rec);
for (;;) {
- if (rec == page_get_infimum_rec(prev_page)) {
+ if (page_rec_is_infimum(rec)) {
/* We cannot go to yet a previous page, because we
do not have the x-latch on it, and cannot acquire one
@@ -2374,12 +2369,12 @@ ibuf_get_volume_buffered(
count_later:
rec = btr_pcur_get_rec(pcur);
- if (rec != page_get_supremum_rec(page)) {
+ if (!page_rec_is_supremum(rec)) {
rec = page_rec_get_next(rec);
}
for (;;) {
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
break;
}
@@ -2414,7 +2409,7 @@ count_later:
rec = page_rec_get_next(rec);
for (;;) {
- if (rec == page_get_supremum_rec(next_page)) {
+ if (page_rec_is_supremum(rec)) {
/* We give up */
@@ -2815,7 +2810,7 @@ ibuf_insert_to_index_page(
ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry));
- if (index->table->comp != page_is_comp(page)) {
+ if (UNIV_UNLIKELY(index->table->comp != (ibool)!!page_is_comp(page))) {
fputs(
"InnoDB: Trying to insert a record from the insert buffer to an index page\n"
"InnoDB: but the 'compact' flag does not match!\n", stderr);
@@ -2824,7 +2819,8 @@ ibuf_insert_to_index_page(
rec = page_rec_get_next(page_get_infimum_rec(page));
- if (rec_get_n_fields(rec, index) != dtuple_get_n_fields(entry)) {
+ if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
+ != dtuple_get_n_fields(entry))) {
fputs(
"InnoDB: Trying to insert a record from the insert buffer to an index page\n"
"InnoDB: but the number of fields does not match!\n", stderr);
@@ -2848,7 +2844,7 @@ ibuf_insert_to_index_page(
if (low_match == dtuple_get_n_fields(entry)) {
rec = page_cur_get_rec(&page_cur);
- btr_cur_del_unmark_for_ibuf(rec, index, mtr);
+ btr_cur_del_unmark_for_ibuf(rec, mtr);
} else {
rec = page_cur_tuple_insert(&page_cur, entry, index, mtr);
@@ -2861,8 +2857,8 @@ ibuf_insert_to_index_page(
PAGE_CUR_LE, &page_cur);
/* This time the record must fit */
- if (!page_cur_tuple_insert(&page_cur, entry,
- index, mtr)) {
+ if (UNIV_UNLIKELY(!page_cur_tuple_insert(
+ &page_cur, entry, index, mtr))) {
ut_print_timestamp(stderr);
@@ -2969,7 +2965,9 @@ ibuf_delete_rec(
btr_pcur_commit_specify_mtr(pcur, mtr);
fputs("InnoDB: Validating insert buffer tree:\n", stderr);
- ut_a(btr_validate_tree(ibuf_data->index->tree));
+ if (!btr_validate_tree(ibuf_data->index->tree, NULL)) {
+ ut_error;
+ }
fprintf(stderr, "InnoDB: ibuf tree ok\n");
fflush(stderr);
diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h
index 0b19e64d4e0..1f3a32fa70c 100644
--- a/innobase/include/btr0btr.h
+++ b/innobase/include/btr0btr.h
@@ -168,7 +168,7 @@ btr_create(
ulint type, /* in: type of the index */
ulint space, /* in: space where created */
dulint index_id,/* in: index id */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr); /* in: mini-transaction handle */
/****************************************************************
Frees a B-tree except the root page, which MUST be freed after this
@@ -276,7 +276,7 @@ void
btr_set_min_rec_mark(
/*=================*/
rec_t* rec, /* in: record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Deletes on the upper level the node pointer to a page. */
@@ -336,7 +336,7 @@ btr_parse_set_min_rec_mark(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/***************************************************************
@@ -398,6 +398,7 @@ btr_page_free_low(
page_t* page, /* in: page to be freed, x-latched */
ulint level, /* in: page level */
mtr_t* mtr); /* in: mtr */
+#ifdef UNIV_BTR_PRINT
/*****************************************************************
Prints size info of a B-tree. */
@@ -414,6 +415,7 @@ btr_print_tree(
dict_tree_t* tree, /* in: tree */
ulint width); /* in: print this many entries from start
and end */
+#endif /* UNIV_BTR_PRINT */
/****************************************************************
Checks the size and number of fields in a record based on the definition of
the index. */
@@ -434,7 +436,8 @@ ibool
btr_validate_tree(
/*==============*/
/* out: TRUE if ok */
- dict_tree_t* tree); /* in: tree */
+ dict_tree_t* tree, /* in: tree */
+ trx_t* trx); /* in: transaction or NULL */
#define BTR_N_LEAF_PAGES 1
#define BTR_TOTAL_SIZE 2
diff --git a/innobase/include/btr0btr.ic b/innobase/include/btr0btr.ic
index 1d1f97d3668..a0860b1c3a7 100644
--- a/innobase/include/btr0btr.ic
+++ b/innobase/include/btr0btr.ic
@@ -200,10 +200,10 @@ btr_node_ptr_get_child_page_no(
page_no = mach_read_from_4(field);
- if (page_no == 0) {
+ if (UNIV_UNLIKELY(page_no == 0)) {
fprintf(stderr,
"InnoDB: a nonsensical page number 0 in a node ptr record at offset %lu\n",
- (unsigned long)(rec - buf_frame_align(rec)));
+ (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE));
buf_page_print(buf_frame_align(rec));
}
diff --git a/innobase/include/btr0cur.h b/innobase/include/btr0cur.h
index 0a8d8ceaeb7..352d1739b6a 100644
--- a/innobase/include/btr0cur.h
+++ b/innobase/include/btr0cur.h
@@ -284,7 +284,6 @@ void
btr_cur_del_unmark_for_ibuf(
/*========================*/
rec_t* rec, /* in: record to delete unmark */
- dict_index_t* index, /* in: record descriptor */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Tries to compress a page of the tree on the leaf level. It is assumed
@@ -389,7 +388,6 @@ btr_cur_parse_del_mark_set_sec_rec(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: index corresponding to page */
page_t* page); /* in: page or NULL */
/***********************************************************************
Estimates the number of rows in a given index range. */
diff --git a/innobase/include/btr0cur.ic b/innobase/include/btr0cur.ic
index dcad3e9e14d..bf8a6efb68d 100644
--- a/innobase/include/btr0cur.ic
+++ b/innobase/include/btr0cur.ic
@@ -52,7 +52,9 @@ btr_cur_get_page(
/* out: pointer to page */
btr_cur_t* cursor) /* in: tree cursor */
{
- return(buf_frame_align(page_cur_get_rec(&(cursor->page_cur))));
+ page_t* page = buf_frame_align(page_cur_get_rec(&(cursor->page_cur)));
+ ut_ad(!!page_is_comp(page) == cursor->index->table->comp);
+ return(page);
}
/*************************************************************
diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h
index 5ee323f1b1e..ae8d0411c12 100644
--- a/innobase/include/buf0buf.h
+++ b/innobase/include/buf0buf.h
@@ -56,9 +56,11 @@ Created 11/5/1995 Heikki Tuuri
#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
extern buf_pool_t* buf_pool; /* The buffer pool of the database */
+#ifdef UNIV_DEBUG
extern ibool buf_debug_prints;/* If this is set TRUE, the program
prints info whenever read or flush
occurs */
+#endif /* UNIV_DEBUG */
extern ulint srv_buf_pool_write_requests; /* variable to count write request
issued */
@@ -382,10 +384,10 @@ Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */
UNIV_INLINE
dulint
-buf_frame_get_modify_clock(
+buf_block_get_modify_clock(
/*=======================*/
/* out: value */
- buf_frame_t* frame); /* in: pointer to a frame */
+ buf_block_t* block); /* in: block */
/************************************************************************
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value
@@ -480,12 +482,20 @@ buf_pool_is_block(
/*==============*/
/* out: TRUE if pointer to block */
void* ptr); /* in: pointer to memory */
+#ifdef UNIV_DEBUG
/*************************************************************************
Validates the buffer pool data structure. */
ibool
buf_validate(void);
/*==============*/
+/*************************************************************************
+Prints info of the buffer pool data structure. */
+
+void
+buf_print(void);
+/*============*/
+#endif /* UNIV_DEBUG */
/************************************************************************
Prints a page to stderr. */
@@ -494,12 +504,6 @@ buf_page_print(
/*===========*/
byte* read_buf); /* in: a database page */
/*************************************************************************
-Prints info of the buffer pool data structure. */
-
-void
-buf_print(void);
-/*============*/
-/*************************************************************************
Returns the number of latched pages in the buffer pool. */
ulint
diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic
index 681a0ef000a..d949254d47d 100644
--- a/innobase/include/buf0buf.ic
+++ b/innobase/include/buf0buf.ic
@@ -11,10 +11,11 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0rea.h"
#include "mtr0mtr.h"
+#ifdef UNIV_DEBUG
extern ulint buf_dbg_counter; /* This is used to insert validation
operations in execution in the
debug version */
-
+#endif /* UNIV_DEBUG */
/************************************************************************
Recommends a move of a block to the start of the LRU list if there is danger
of dropping from the buffer pool. NOTE: does not reserve the buffer pool
@@ -26,12 +27,8 @@ buf_block_peek_if_too_old(
/* out: TRUE if should be made younger */
buf_block_t* block) /* in: block to make younger */
{
- if (buf_pool->freed_page_clock >= block->freed_page_clock
- + 1 + (buf_pool->curr_size / 1024)) {
- return(TRUE);
- }
-
- return(FALSE);
+ return(buf_pool->freed_page_clock >= block->freed_page_clock
+ + 1 + (buf_pool->curr_size / 1024));
}
/*************************************************************************
@@ -210,8 +207,8 @@ buf_block_align(
frame_zero = buf_pool->frame_zero;
- if ((ulint)ptr < (ulint)frame_zero
- || (ulint)ptr > (ulint)(buf_pool->high_end)) {
+ if (UNIV_UNLIKELY((ulint)ptr < (ulint)frame_zero)
+ || UNIV_UNLIKELY((ulint)ptr > (ulint)(buf_pool->high_end))) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -246,8 +243,8 @@ buf_frame_align(
frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
- if (((ulint)frame < (ulint)(buf_pool->frame_zero))
- || (ulint)frame >= (ulint)(buf_pool->high_end)) {
+ if (UNIV_UNLIKELY((ulint)frame < (ulint)(buf_pool->frame_zero))
+ || UNIV_UNLIKELY((ulint)frame >= (ulint)(buf_pool->high_end))) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -485,17 +482,11 @@ Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */
UNIV_INLINE
dulint
-buf_frame_get_modify_clock(
+buf_block_get_modify_clock(
/*=======================*/
/* out: value */
- buf_frame_t* frame) /* in: pointer to a frame */
+ buf_block_t* block) /* in: block */
{
- buf_block_t* block;
-
- ut_ad(frame);
-
- block = buf_block_align(frame);
-
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
diff --git a/innobase/include/buf0lru.h b/innobase/include/buf0lru.h
index 45164dd561e..fb29b44ba98 100644
--- a/innobase/include/buf0lru.h
+++ b/innobase/include/buf0lru.h
@@ -122,6 +122,7 @@ void
buf_LRU_make_block_old(
/*===================*/
buf_block_t* block); /* in: control block */
+#ifdef UNIV_DEBUG
/**************************************************************************
Validates the LRU list. */
@@ -134,6 +135,7 @@ Prints the LRU list. */
void
buf_LRU_print(void);
/*===============*/
+#endif /* UNIV_DEBUG */
#ifndef UNIV_NONINL
#include "buf0lru.ic"
diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h
index a4d2c1a2e1d..7e9692eca5a 100644
--- a/innobase/include/data0type.h
+++ b/innobase/include/data0type.h
@@ -12,7 +12,7 @@ Created 1/16/1996 Heikki Tuuri
#include "univ.i"
extern ulint data_mysql_default_charset_coll;
-extern ulint data_mysql_latin1_swedish_charset_coll;
+#define DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL 8
/* SQL data type struct */
typedef struct dtype_struct dtype_t;
diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic
index a87a08ca582..06d45dd5501 100644
--- a/innobase/include/data0type.ic
+++ b/innobase/include/data0type.ic
@@ -388,8 +388,8 @@ dtype_get_fixed_size(
dtype_get_charset_coll(type->prtype),
&mbminlen, &mbmaxlen);
- if (type->mbminlen != mbminlen
- || type->mbmaxlen != mbmaxlen) {
+ if (UNIV_UNLIKELY(type->mbminlen != mbminlen)
+ || UNIV_UNLIKELY(type->mbmaxlen != mbmaxlen)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: "
diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h
index abee62300e3..1df976a5301 100644
--- a/innobase/include/dyn0dyn.h
+++ b/innobase/include/dyn0dyn.h
@@ -132,7 +132,7 @@ void
dyn_push_string(
/*============*/
dyn_array_t* arr, /* in: dyn array */
- byte* str, /* in: string to write */
+ const byte* str, /* in: string to write */
ulint len); /* in: string length */
/*#################################################################*/
diff --git a/innobase/include/dyn0dyn.ic b/innobase/include/dyn0dyn.ic
index b6c4808398b..c1b8f2cb8ce 100644
--- a/innobase/include/dyn0dyn.ic
+++ b/innobase/include/dyn0dyn.ic
@@ -324,10 +324,9 @@ void
dyn_push_string(
/*============*/
dyn_array_t* arr, /* in: dyn array */
- byte* str, /* in: string to write */
+ const byte* str, /* in: string to write */
ulint len) /* in: string length */
{
- byte* ptr;
ulint n_copied;
while (len > 0) {
@@ -337,9 +336,7 @@ dyn_push_string(
n_copied = len;
}
- ptr = (byte*) dyn_array_push(arr, n_copied);
-
- ut_memcpy(ptr, str, n_copied);
+ memcpy(dyn_array_push(arr, n_copied), str, n_copied);
str += n_copied;
len -= n_copied;
diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h
index 45a81a4ac77..20b1f1d7145 100644
--- a/innobase/include/lock0lock.h
+++ b/innobase/include/lock0lock.h
@@ -19,7 +19,9 @@ Created 5/7/1996 Heikki Tuuri
#include "read0types.h"
#include "hash0hash.h"
+#ifdef UNIV_DEBUG
extern ibool lock_print_waits;
+#endif /* UNIV_DEBUG */
/* Buffer for storing information about the most recent deadlock error */
extern FILE* lock_latest_err_file;
@@ -216,6 +218,7 @@ actual record is being moved. */
void
lock_rec_store_on_page_infimum(
/*===========================*/
+ page_t* page, /* in: page containing the record */
rec_t* rec); /* in: record whose lock state is stored
on the infimum record of the same page; lock
bits are reset on the record */
@@ -412,9 +415,7 @@ lock_table(
/* out: DB_SUCCESS, DB_LOCK_WAIT,
DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing;
- if LOCK_TABLE_EXP bits are set,
- creates an explicit table lock */
+ does nothing */
dict_table_t* table, /* in: database table in dictionary cache */
ulint mode, /* in: lock mode */
que_thr_t* thr); /* in: query thread */
@@ -451,15 +452,6 @@ lock_release_off_kernel(
/*====================*/
trx_t* trx); /* in: transaction */
/*************************************************************************
-Releases table locks explicitly requested with LOCK TABLES (indicated by
-lock type LOCK_TABLE_EXP), and releases possible other transactions waiting
-because of these locks. */
-
-void
-lock_release_tables_off_kernel(
-/*===========================*/
- trx_t* trx); /* in: transaction */
-/*************************************************************************
Cancels a waiting lock request and releases possible other transactions
waiting behind it. */
@@ -618,9 +610,6 @@ extern lock_sys_t* lock_sys;
/* Lock types */
#define LOCK_TABLE 16 /* these type values should be so high that */
#define LOCK_REC 32 /* they can be ORed to the lock mode */
-#define LOCK_TABLE_EXP 80 /* explicit table lock (80 = 16 + 64) */
-#define LOCK_TABLE_TRANSACTIONAL 144
- /* transactional table lock (144 = 16 + 128)*/
#define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the
type_mode field in a lock */
/* Waiting lock flag */
diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h
index d14a116072d..7f3f10438b4 100644
--- a/innobase/include/log0log.h
+++ b/innobase/include/log0log.h
@@ -17,8 +17,12 @@ Created 12/9/1995 Heikki Tuuri
typedef struct log_struct log_t;
typedef struct log_group_struct log_group_t;
+#ifdef UNIV_DEBUG
extern ibool log_do_write;
extern ibool log_debug_writes;
+#else /* UNIV_DEBUG */
+# define log_do_write TRUE
+#endif /* UNIV_DEBUG */
/* Wait modes for log_write_up_to */
#define LOG_NO_WAIT 91
diff --git a/innobase/include/mach0data.h b/innobase/include/mach0data.h
index 7ad760cd60f..f9a3ff521d5 100644
--- a/innobase/include/mach0data.h
+++ b/innobase/include/mach0data.h
@@ -52,6 +52,27 @@ mach_read_from_2(
/*=============*/
/* out: ulint integer, >= 0, < 64k */
byte* b); /* in: pointer to two bytes */
+
+/************************************************************
+The following function is used to convert a 16-bit data item
+to the canonical format, for fast bytewise equality test
+against memory. */
+UNIV_INLINE
+uint16
+mach_encode_2(
+/*==========*/
+ /* out: 16-bit integer in canonical format */
+ ulint n); /* in: integer in machine-dependent format */
+/************************************************************
+The following function is used to convert a 16-bit data item
+from the canonical format, for fast bytewise equality test
+against memory. */
+UNIV_INLINE
+ulint
+mach_decode_2(
+/*==========*/
+ /* out: integer in machine-dependent format */
+ uint16 n); /* in: 16-bit integer in canonical format */
/***********************************************************
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
diff --git a/innobase/include/mach0data.ic b/innobase/include/mach0data.ic
index 3ffb9baa344..888f3f743e4 100644
--- a/innobase/include/mach0data.ic
+++ b/innobase/include/mach0data.ic
@@ -68,6 +68,37 @@ mach_read_from_2(
);
}
+/************************************************************
+The following function is used to convert a 16-bit data item
+to the canonical format, for fast bytewise equality test
+against memory. */
+UNIV_INLINE
+uint16
+mach_encode_2(
+/*==========*/
+ /* out: 16-bit integer in canonical format */
+ ulint n) /* in: integer in machine-dependent format */
+{
+ uint16 ret;
+ ut_ad(2 == sizeof ret);
+ mach_write_to_2((byte*) &ret, n);
+ return(ret);
+}
+/************************************************************
+The following function is used to convert a 16-bit data item
+from the canonical format, for fast bytewise equality test
+against memory. */
+UNIV_INLINE
+ulint
+mach_decode_2(
+/*==========*/
+ /* out: integer in machine-dependent format */
+ uint16 n) /* in: 16-bit integer in canonical format */
+{
+ ut_ad(2 == sizeof n);
+ return(mach_read_from_2((byte*) &n));
+}
+
/***********************************************************
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic
index 82d88099c3f..8c87c884d78 100644
--- a/innobase/include/mem0mem.ic
+++ b/innobase/include/mem0mem.ic
@@ -623,7 +623,7 @@ mem_strdupq(
}
*d++ = q;
*d++ = '\0';
- ut_ad(len == d - dst);
+ ut_ad((ssize_t) len == d - dst);
return(dst);
}
diff --git a/innobase/include/mtr0log.h b/innobase/include/mtr0log.h
index c0636ea1e1e..6a3920aa8a1 100644
--- a/innobase/include/mtr0log.h
+++ b/innobase/include/mtr0log.h
@@ -41,10 +41,10 @@ corresponding log record to the mini-transaction log. */
void
mlog_write_string(
/*==============*/
- byte* ptr, /* in: pointer where to write */
- byte* str, /* in: string to write */
- ulint len, /* in: string length */
- mtr_t* mtr); /* in: mini-transaction handle */
+ byte* ptr, /* in: pointer where to write */
+ const byte* str, /* in: string to write */
+ ulint len, /* in: string length */
+ mtr_t* mtr); /* in: mini-transaction handle */
/************************************************************
Writes initial part of a log record consisting of one-byte item
type and four-byte space and page numbers. */
@@ -85,9 +85,9 @@ Catenates n bytes to the mtr log. */
void
mlog_catenate_string(
/*=================*/
- mtr_t* mtr, /* in: mtr */
- byte* str, /* in: string to write */
- ulint len); /* in: string length */
+ mtr_t* mtr, /* in: mtr */
+ const byte* str, /* in: string to write */
+ ulint len); /* in: string length */
/************************************************************
Catenates a compressed ulint to mlog. */
UNIV_INLINE
diff --git a/innobase/include/mtr0mtr.h b/innobase/include/mtr0mtr.h
index 071279d5259..f44e813cf6b 100644
--- a/innobase/include/mtr0mtr.h
+++ b/innobase/include/mtr0mtr.h
@@ -112,7 +112,11 @@ flag value must give the length also! */
/* mark compact clustered index
record deleted */
#define MLOG_COMP_REC_SEC_DELETE_MARK ((byte)40)/* mark compact secondary index
- record deleted */
+ record deleted; this log
+ record type is redundant, as
+ MLOG_REC_SEC_DELETE_MARK is
+ independent of the record
+ format. */
#define MLOG_COMP_REC_UPDATE_IN_PLACE ((byte)41)/* update of a compact record,
preserves record field sizes */
#define MLOG_COMP_REC_DELETE ((byte)42) /* delete a compact record
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index f55c345537e..362e3552411 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -17,6 +17,8 @@ Created 10/21/1995 Heikki Tuuri
#include <time.h>
#endif
+typedef struct fil_node_struct fil_node_t;
+
extern ibool os_do_not_call_flush_at_each_write;
extern ibool os_has_said_disk_full;
extern ibool os_aio_print_debug;
@@ -371,7 +373,7 @@ os_file_get_size_as_iblonglong(
/* out: size in bytes, -1 if error */
os_file_t file); /* in: handle to a file */
/***************************************************************************
-Sets a file size. This function can be used to extend or truncate a file. */
+Write the specified number of zeros to a newly created file. */
ibool
os_file_set_size(
@@ -563,7 +565,7 @@ os_aio(
ulint offset_high, /* in: most significant 32 bits of
offset */
ulint n, /* in: number of bytes to read or write */
- void* message1,/* in: messages for the aio handler (these
+ fil_node_t* message1,/* in: messages for the aio handler (these
can be used to identify a completed aio
operation); if mode is OS_AIO_SYNC, these
are ignored */
@@ -621,7 +623,7 @@ os_aio_windows_handle(
ignored */
ulint pos, /* this parameter is used only in sync aio:
wait for the aio slot at this position */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -641,7 +643,7 @@ os_aio_posix_handle(
/*================*/
/* out: TRUE if the aio operation succeeded */
ulint array_no, /* in: array number 0 - 3 */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -661,7 +663,7 @@ os_aio_simulated_handle(
i/o thread, segment 1 the log i/o thread,
then follow the non-ibuf read threads, and as
the last are the non-ibuf write threads */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -688,6 +690,8 @@ Refreshes the statistics used to print per-second averages. */
void
os_aio_refresh_stats(void);
/*======================*/
+
+#ifdef UNIV_DEBUG
/**************************************************************************
Checks that all slots in the system have been freed, that is, there are
no pending io operations. */
@@ -695,6 +699,7 @@ no pending io operations. */
ibool
os_aio_all_slots_free(void);
/*=======================*/
+#endif /* UNIV_DEBUG */
/***********************************************************************
This function returns information about the specified file */
diff --git a/innobase/include/page0cur.h b/innobase/include/page0cur.h
index 4fc62f37db7..b03302b0e77 100644
--- a/innobase/include/page0cur.h
+++ b/innobase/include/page0cur.h
@@ -26,11 +26,13 @@ Created 10/4/1994 Heikki Tuuri
#define PAGE_CUR_GE 2
#define PAGE_CUR_L 3
#define PAGE_CUR_LE 4
-#define PAGE_CUR_LE_OR_EXTENDS 5 /* This is a search mode used in
+/*#define PAGE_CUR_LE_OR_EXTENDS 5*/ /* This is a search mode used in
"column LIKE 'abc%' ORDER BY column DESC";
we have to find strings which are <= 'abc' or
which extend it */
-#define PAGE_CUR_DBG 6
+#ifdef UNIV_SEARCH_DEBUG
+# define PAGE_CUR_DBG 6 /* As PAGE_CUR_LE, but skips search shortcut */
+#endif /* UNIV_SEARCH_DEBUG */
#ifdef PAGE_CUR_ADAPT
# ifdef UNIV_SEARCH_PERF_STAT
@@ -78,16 +80,16 @@ UNIV_INLINE
ibool
page_cur_is_before_first(
/*=====================*/
- /* out: TRUE if at start */
- page_cur_t* cur); /* in: cursor */
+ /* out: TRUE if at start */
+ const page_cur_t* cur); /* in: cursor */
/*************************************************************
Returns TRUE if the cursor is after last user record. */
UNIV_INLINE
ibool
page_cur_is_after_last(
/*===================*/
- /* out: TRUE if at end */
- page_cur_t* cur); /* in: cursor */
+ /* out: TRUE if at end */
+ const page_cur_t* cur); /* in: cursor */
/**************************************************************
Positions the cursor on the given record. */
UNIV_INLINE
diff --git a/innobase/include/page0cur.ic b/innobase/include/page0cur.ic
index e99d799b372..f8346819e84 100644
--- a/innobase/include/page0cur.ic
+++ b/innobase/include/page0cur.ic
@@ -69,15 +69,10 @@ UNIV_INLINE
ibool
page_cur_is_before_first(
/*=====================*/
- /* out: TRUE if at start */
- page_cur_t* cur) /* in: cursor */
+ /* out: TRUE if at start */
+ const page_cur_t* cur) /* in: cursor */
{
- if (page_get_infimum_rec(page_cur_get_page(cur)) == cur->rec) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(page_rec_is_infimum(cur->rec));
}
/*************************************************************
@@ -86,15 +81,10 @@ UNIV_INLINE
ibool
page_cur_is_after_last(
/*===================*/
- /* out: TRUE if at end */
- page_cur_t* cur) /* in: cursor */
+ /* out: TRUE if at end */
+ const page_cur_t* cur) /* in: cursor */
{
- if (page_get_supremum_rec(page_cur_get_page(cur)) == cur->rec) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(page_rec_is_supremum(cur->rec));
}
/**************************************************************
diff --git a/innobase/include/page0page.h b/innobase/include/page0page.h
index 144c297b811..c4ffa39d3ac 100644
--- a/innobase/include/page0page.h
+++ b/innobase/include/page0page.h
@@ -373,13 +373,21 @@ page_dir_find_owner_slot(
/****************************************************************
Determine whether the page is in new-style compact format. */
UNIV_INLINE
-ibool
+ulint
page_is_comp(
/*=========*/
- /* out: TRUE if the page is in compact format
- FALSE if it is in old-style format */
+ /* out: nonzero if the page is in compact
+ format, zero if it is in old-style format */
page_t* page); /* in: index page */
/****************************************************************
+TRUE if the record is on a page in compact format. */
+UNIV_INLINE
+ulint
+page_rec_is_comp(
+/*=============*/
+ /* out: nonzero if in compact format */
+ const rec_t* rec); /* in: record */
+/****************************************************************
Gets the pointer to the next record on the page. */
UNIV_INLINE
rec_t*
@@ -407,47 +415,55 @@ page_rec_get_prev(
/* out: pointer to previous record */
rec_t* rec); /* in: pointer to record,
must not be page infimum */
-
/****************************************************************
TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
-page_rec_is_user_rec(
-/*=================*/
+page_rec_is_user_rec_low(
+/*=====================*/
/* out: TRUE if a user record */
- rec_t* rec); /* in: record */
+ ulint offset);/* in: record offset on page */
/****************************************************************
TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_supremum(
-/*=================*/
+page_rec_is_supremum_low(
+/*=====================*/
/* out: TRUE if the supremum record */
- rec_t* rec); /* in: record */
+ ulint offset);/* in: record offset on page */
/****************************************************************
TRUE if the record is the infimum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_infimum(
-/*================*/
+page_rec_is_infimum_low(
+/*=====================*/
/* out: TRUE if the infimum record */
- rec_t* rec); /* in: record */
+ ulint offset);/* in: record offset on page */
+
/****************************************************************
-TRUE if the record is the first user record on the page. */
+TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
-page_rec_is_first_user_rec(
-/*=======================*/
- /* out: TRUE if first user record */
- rec_t* rec); /* in: record */
+page_rec_is_user_rec(
+/*=================*/
+ /* out: TRUE if a user record */
+ const rec_t* rec); /* in: record */
/****************************************************************
-TRUE if the record is the last user record on the page. */
+TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_last_user_rec(
-/*======================*/
- /* out: TRUE if last user record */
- rec_t* rec); /* in: record */
+page_rec_is_supremum(
+/*=================*/
+ /* out: TRUE if the supremum record */
+ const rec_t* rec); /* in: record */
+/****************************************************************
+TRUE if the record is the infimum record on a page. */
+UNIV_INLINE
+ibool
+page_rec_is_infimum(
+/*================*/
+ /* out: TRUE if the infimum record */
+ const rec_t* rec); /* in: record */
/*******************************************************************
Looks for the record which owns the given record. */
UNIV_INLINE
@@ -495,7 +511,7 @@ ulint
page_get_free_space_of_empty(
/*=========================*/
/* out: free space */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
__attribute__((const));
/****************************************************************
Returns the sum of the sizes of the records in the record list
@@ -539,7 +555,7 @@ page_create(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/*****************************************************************
Differs from page_copy_rec_list_end, because this function does not
touch the lock table and max trx id on page. */
@@ -673,7 +689,7 @@ page_parse_create(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/****************************************************************
diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic
index bc0805ca30c..fd5281fdbec 100644
--- a/innobase/include/page0page.ic
+++ b/innobase/include/page0page.ic
@@ -155,14 +155,27 @@ page_header_reset_last_insert(
/****************************************************************
Determine whether the page is in new-style compact format. */
UNIV_INLINE
-ibool
+ulint
page_is_comp(
/*=========*/
- /* out: TRUE if the page is in compact format
- FALSE if it is in old-style format */
- page_t* page) /* in: index page */
+ /* out: nonzero if the page is in compact
+ format, zero if it is in old-style format */
+ page_t* page) /* in: index page */
+{
+ return(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
+ 0x8000));
+}
+
+/****************************************************************
+TRUE if the record is on a page in compact format. */
+UNIV_INLINE
+ulint
+page_rec_is_comp(
+/*=============*/
+ /* out: nonzero if in compact format */
+ const rec_t* rec) /* in: record */
{
- return(!!(page_header_get_field(page, PAGE_N_HEAP) & 0x8000));
+ return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE)));
}
/****************************************************************
@@ -205,112 +218,107 @@ page_get_supremum_rec(
TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
-page_rec_is_user_rec(
-/*=================*/
+page_rec_is_user_rec_low(
+/*=====================*/
/* out: TRUE if a user record */
- rec_t* rec) /* in: record */
+ ulint offset) /* in: record offset on page */
{
- ut_ad(rec);
-
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
- return(FALSE);
- }
-
- if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
-
- return(FALSE);
- }
+ ut_ad(offset >= PAGE_NEW_INFIMUM);
+#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
+# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
+#endif
+#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
+# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
+#endif
+#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
+# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
+#endif
+#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
+# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
+#endif
+#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
+# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
+#endif
+#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
+# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
+#endif
+ ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
- return(TRUE);
+ return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
+ && UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
+ && UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
+ && UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
}
/****************************************************************
TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_supremum(
-/*=================*/
+page_rec_is_supremum_low(
+/*=====================*/
/* out: TRUE if the supremum record */
- rec_t* rec) /* in: record */
+ ulint offset) /* in: record offset on page */
{
- ut_ad(rec);
+ ut_ad(offset >= PAGE_NEW_INFIMUM);
+ ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
+ || UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
}
/****************************************************************
TRUE if the record is the infimum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_infimum(
-/*================*/
+page_rec_is_infimum_low(
+/*=====================*/
/* out: TRUE if the infimum record */
- rec_t* rec) /* in: record */
+ ulint offset) /* in: record offset on page */
{
- ut_ad(rec);
-
- if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
-
- return(TRUE);
- }
+ ut_ad(offset >= PAGE_NEW_INFIMUM);
+ ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
- return(FALSE);
+ return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
+ || UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
}
/****************************************************************
-TRUE if the record is the first user record on the page. */
+TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
-page_rec_is_first_user_rec(
-/*=======================*/
- /* out: TRUE if first user record */
- rec_t* rec) /* in: record */
+page_rec_is_user_rec(
+/*=================*/
+ /* out: TRUE if a user record */
+ const rec_t* rec) /* in: record */
{
- ut_ad(rec);
-
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
- return(FALSE);
- }
-
- if (rec == page_rec_get_next(
- page_get_infimum_rec(buf_frame_align(rec)))) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(page_rec_is_user_rec_low(
+ ut_align_offset(rec, UNIV_PAGE_SIZE)));
}
/****************************************************************
-TRUE if the record is the last user record on the page. */
+TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
-page_rec_is_last_user_rec(
-/*======================*/
- /* out: TRUE if last user record */
- rec_t* rec) /* in: record */
+page_rec_is_supremum(
+/*=================*/
+ /* out: TRUE if the supremum record */
+ const rec_t* rec) /* in: record */
{
- ut_ad(rec);
-
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
- return(FALSE);
- }
-
- if (page_rec_get_next(rec)
- == page_get_supremum_rec(buf_frame_align(rec))) {
-
- return(TRUE);
- }
+ return(page_rec_is_supremum_low(
+ ut_align_offset(rec, UNIV_PAGE_SIZE)));
+}
- return(FALSE);
+/****************************************************************
+TRUE if the record is the infimum record on a page. */
+UNIV_INLINE
+ibool
+page_rec_is_infimum(
+/*================*/
+ /* out: TRUE if the infimum record */
+ const rec_t* rec) /* in: record */
+{
+ return(page_rec_is_infimum_low(
+ ut_align_offset(rec, UNIV_PAGE_SIZE)));
}
/*****************************************************************
@@ -340,22 +348,26 @@ page_cmp_dtuple_rec_with_match(
matched; when function returns contains the
value for current comparison */
{
- page_t* page;
+ ulint rec_offset;
ut_ad(dtuple_check_typed(dtuple));
ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
- page = buf_frame_align(rec);
+ rec_offset = ut_align_offset(rec, UNIV_PAGE_SIZE);
- if (rec == page_get_infimum_rec(page)) {
+ if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
+ || UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
return(1);
- } else if (rec == page_get_supremum_rec(page)) {
+ }
+ if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
+ || UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
return(-1);
- } else {
- return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
+ }
+
+ return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
matched_fields,
matched_bytes));
- }
}
/*****************************************************************
@@ -482,7 +494,7 @@ page_dir_slot_set_rec(
{
ut_ad(page_rec_check(rec));
- mach_write_to_2(slot, rec - buf_frame_align(rec));
+ mach_write_to_2(slot, ut_align_offset(rec, UNIV_PAGE_SIZE));
}
/*******************************************************************
@@ -494,8 +506,8 @@ page_dir_slot_get_n_owned(
/* out: number of records */
page_dir_slot_t* slot) /* in: page directory slot */
{
- return(rec_get_n_owned(page_dir_slot_get_rec(slot),
- page_is_comp(buf_frame_align(slot))));
+ rec_t* rec = page_dir_slot_get_rec(slot);
+ return(rec_get_n_owned(rec, page_rec_is_comp(rec)));
}
/*******************************************************************
@@ -508,8 +520,8 @@ page_dir_slot_set_n_owned(
ulint n) /* in: number of records owned
by the slot */
{
- rec_set_n_owned(page_dir_slot_get_rec(slot),
- page_is_comp(buf_frame_align(slot)), n);
+ rec_t* rec = page_dir_slot_get_rec(slot);
+ rec_set_n_owned(rec, page_rec_is_comp(rec), n);
}
/****************************************************************
@@ -540,26 +552,25 @@ page_rec_get_next(
ut_ad(page_rec_check(rec));
- page = buf_frame_align(rec);
+ page = ut_align_down(rec, UNIV_PAGE_SIZE);
offs = rec_get_next_offs(rec, page_is_comp(page));
- if (offs >= UNIV_PAGE_SIZE) {
- fprintf(stderr,
-"InnoDB: Next record offset is nonsensical %lu in record at offset %lu\n",
- (ulong)offs, (ulong)(rec - page));
+ if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
fprintf(stderr,
-"\nInnoDB: rec address %p, first buffer frame %p\n"
+"InnoDB: Next record offset is nonsensical %lu in record at offset %lu\n"
+"InnoDB: rec address %p, first buffer frame %p\n"
"InnoDB: buffer pool high end %p, buf fix count %lu\n",
+ (ulong)offs, (ulong)(rec - page),
rec, buf_pool->frame_zero,
buf_pool->high_end,
(ulong)buf_block_align(rec)->buf_fix_count);
buf_page_print(page);
- ut_a(0);
+ ut_error;
}
- if (offs == 0) {
+ if (UNIV_UNLIKELY(offs == 0)) {
return(NULL);
}
@@ -581,15 +592,12 @@ page_rec_set_next(
ulint offs;
ut_ad(page_rec_check(rec));
- ut_a((next == NULL)
- || (buf_frame_align(rec) == buf_frame_align(next)));
-
- page = buf_frame_align(rec);
-
- ut_ad(rec != page_get_supremum_rec(page));
- ut_ad(next != page_get_infimum_rec(page));
+ ut_ad(!page_rec_is_supremum(rec));
+ page = ut_align_down(rec, UNIV_PAGE_SIZE);
if (next) {
+ ut_ad(!page_rec_is_infimum(next));
+ ut_ad(page == ut_align_down(next, UNIV_PAGE_SIZE));
offs = (ulint) (next - page);
} else {
offs = 0;
@@ -613,13 +621,12 @@ page_rec_get_prev(
rec_t* rec2;
rec_t* prev_rec = NULL;
page_t* page;
- ibool comp;
ut_ad(page_rec_check(rec));
- page = buf_frame_align(rec);
+ page = ut_align_down(rec, UNIV_PAGE_SIZE);
- ut_ad(rec != page_get_infimum_rec(page));
+ ut_ad(!page_rec_is_infimum(rec));
slot_no = page_dir_find_owner_slot(rec);
@@ -628,7 +635,6 @@ page_rec_get_prev(
slot = page_dir_get_nth_slot(page, slot_no - 1);
rec2 = page_dir_slot_get_rec(slot);
- comp = page_is_comp(page);
while (rec != rec2) {
prev_rec = rec2;
@@ -649,13 +655,16 @@ page_rec_find_owner_rec(
/* out: the owner record */
rec_t* rec) /* in: the physical record */
{
- ibool comp;
-
ut_ad(page_rec_check(rec));
- comp = page_is_comp(buf_frame_align(rec));
- while (rec_get_n_owned(rec, comp) == 0) {
- rec = page_rec_get_next(rec);
+ if (page_rec_is_comp(rec)) {
+ while (rec_get_n_owned(rec, TRUE) == 0) {
+ rec = page_rec_get_next(rec);
+ }
+ } else {
+ while (rec_get_n_owned(rec, FALSE) == 0) {
+ rec = page_rec_get_next(rec);
+ }
}
return(rec);
@@ -691,10 +700,17 @@ ulint
page_get_free_space_of_empty(
/*=========================*/
/* out: free space */
- ibool comp) /* in: TRUE=compact page layout */
+ ulint comp) /* in: nonzero=compact page layout */
{
+ if (UNIV_LIKELY(comp)) {
+ return((ulint)(UNIV_PAGE_SIZE
+ - PAGE_NEW_SUPREMUM_END
+ - PAGE_DIR
+ - 2 * PAGE_DIR_SLOT_SIZE));
+ }
+
return((ulint)(UNIV_PAGE_SIZE
- - (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END)
+ - PAGE_OLD_SUPREMUM_END
- PAGE_DIR
- 2 * PAGE_DIR_SLOT_SIZE));
}
@@ -716,17 +732,21 @@ page_get_max_insert_size(
{
ulint occupied;
ulint free_space;
- ibool comp;
- comp = page_is_comp(page);
+ if (page_is_comp(page)) {
+ occupied = page_header_get_field(page, PAGE_HEAP_TOP)
+ - PAGE_NEW_SUPREMUM_END + page_dir_calc_reserved_space(
+ n_recs + page_dir_get_n_heap(page) - 2);
- occupied = page_header_get_field(page, PAGE_HEAP_TOP)
- - (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END)
- + page_dir_calc_reserved_space(
+ free_space = page_get_free_space_of_empty(TRUE);
+ } else {
+ occupied = page_header_get_field(page, PAGE_HEAP_TOP)
+ - PAGE_OLD_SUPREMUM_END + page_dir_calc_reserved_space(
n_recs + page_dir_get_n_heap(page) - 2);
- free_space = page_get_free_space_of_empty(comp);
-
+ free_space = page_get_free_space_of_empty(FALSE);
+ }
+
/* Above the 'n_recs +' part reserves directory space for the new
inserted records; the '- 2' excludes page infimum and supremum
records */
@@ -752,14 +772,11 @@ page_get_max_insert_size_after_reorganize(
{
ulint occupied;
ulint free_space;
- ibool comp;
- comp = page_is_comp(page);
-
occupied = page_get_data_size(page)
+ page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
- free_space = page_get_free_space_of_empty(comp);
+ free_space = page_get_free_space_of_empty(page_is_comp(page));
if (occupied > free_space) {
@@ -783,6 +800,7 @@ page_mem_free(
ulint garbage;
ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
free = page_header_get_ptr(page, PAGE_FREE);
page_rec_set_next(rec, free);
diff --git a/innobase/include/read0read.ic b/innobase/include/read0read.ic
index 03d84ee0c51..ec9ef5814bb 100644
--- a/innobase/include/read0read.ic
+++ b/innobase/include/read0read.ic
@@ -71,13 +71,8 @@ read_view_sees_trx_id(
cmp = ut_dulint_cmp(trx_id,
read_view_get_nth_trx_id(view, n_ids - i - 1));
- if (0 == cmp) {
-
- return(FALSE);
-
- } else if (cmp < 0) {
-
- return(TRUE);
+ if (cmp <= 0) {
+ return(cmp < 0);
}
}
diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h
index 134c37c8030..1d15b8d1c77 100644
--- a/innobase/include/rem0rec.h
+++ b/innobase/include/rem0rec.h
@@ -51,7 +51,7 @@ rec_get_next_offs(
/* out: the page offset of the next
chained record */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the next record offset field
of the record. */
@@ -60,7 +60,7 @@ void
rec_set_next_offs(
/*==============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint next); /* in: offset of the next record */
/**********************************************************
The following function is used to get the number of fields
@@ -90,7 +90,7 @@ rec_get_n_owned(
/*============*/
/* out: number of owned records */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the number of owned
records. */
@@ -99,7 +99,7 @@ void
rec_set_n_owned(
/*============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint n_owned); /* in: the number of owned */
/**********************************************************
The following function is used to retrieve the info bits of
@@ -110,7 +110,7 @@ rec_get_info_bits(
/*==============*/
/* out: info bits */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the info bits of a record. */
UNIV_INLINE
@@ -118,7 +118,7 @@ void
rec_set_info_bits(
/*==============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint bits); /* in: info bits */
/**********************************************************
The following function retrieves the status bits of a new-style record. */
@@ -147,7 +147,7 @@ rec_get_info_and_status_bits(
/*=========================*/
/* out: info bits */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the info and status
bits of a record. (Only compact records have status bits.) */
@@ -156,18 +156,18 @@ void
rec_set_info_and_status_bits(
/*=========================*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint bits); /* in: info bits */
/**********************************************************
The following function tells if record is delete marked. */
UNIV_INLINE
-ibool
+ulint
rec_get_deleted_flag(
/*=================*/
- /* out: TRUE if delete marked */
+ /* out: nonzero if delete marked */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the deleted bit. */
UNIV_INLINE
@@ -175,8 +175,8 @@ void
rec_set_deleted_flag(
/*=================*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
- ibool flag); /* in: TRUE if delete marked */
+ ulint comp, /* in: nonzero=compact page format */
+ ulint flag); /* in: nonzero if delete marked */
/**********************************************************
The following function tells if a new-style record is a node pointer. */
UNIV_INLINE
@@ -186,14 +186,6 @@ rec_get_node_ptr_flag(
/* out: TRUE if node pointer */
rec_t* rec); /* in: physical record */
/**********************************************************
-The following function is used to flag a record as a node pointer. */
-UNIV_INLINE
-void
-rec_set_node_ptr_flag(
-/*=================*/
- rec_t* rec, /* in: physical record */
- ibool flag); /* in: TRUE if the record is a node pointer */
-/**********************************************************
The following function is used to get the order number
of the record in the heap of the index page. */
UNIV_INLINE
@@ -202,7 +194,7 @@ rec_get_heap_no(
/*=============*/
/* out: heap order number */
rec_t* rec, /* in: physical record */
- ibool comp); /* in: TRUE=compact page format */
+ ulint comp); /* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the heap number
field in the record. */
@@ -211,7 +203,7 @@ void
rec_set_heap_no(
/*=============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint heap_no);/* in: the heap number */
/**********************************************************
The following function is used to test whether the data offsets
@@ -290,7 +282,7 @@ rec_get_nth_field_size(
ulint n); /* in: index of the field */
/****************************************************************
The following function is used to get a pointer to the nth
-data field in an old-style record. */
+data field in a record. */
UNIV_INLINE
byte*
rec_get_nth_field(
@@ -305,27 +297,18 @@ rec_get_nth_field(
Determine if the offsets are for a record in the new
compact format. */
UNIV_INLINE
-ibool
+ulint
rec_offs_comp(
/*==========*/
- /* out: TRUE if compact format */
+ /* out: nonzero if compact format */
const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**********************************************************
-Returns TRUE if the nth field of rec is SQL NULL. */
+Returns nonzero if the extern bit is set in nth field of rec. */
UNIV_INLINE
-ibool
-rec_offs_nth_null(
-/*==============*/
- /* out: TRUE if SQL NULL */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n); /* in: nth field */
-/**********************************************************
-Returns TRUE if the extern bit is set in nth field of rec. */
-UNIV_INLINE
-ibool
+ulint
rec_offs_nth_extern(
/*================*/
- /* out: TRUE if externally stored */
+ /* out: nonzero if externally stored */
const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint n); /* in: nth field */
/**********************************************************
diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic
index 2593fb8edeb..e2dceb6bae5 100644
--- a/innobase/include/rem0rec.ic
+++ b/innobase/include/rem0rec.ic
@@ -265,7 +265,7 @@ rec_get_next_offs(
/* out: the page offset of the next chained record, or
0 if none */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
ulint field_value;
@@ -312,7 +312,7 @@ void
rec_set_next_offs(
/*==============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint next) /* in: offset of the next record, or 0 if none */
{
ut_ad(rec);
@@ -414,7 +414,7 @@ rec_get_n_fields(
{
ut_ad(rec);
ut_ad(index);
- if (!index->table->comp) {
+ if (UNIV_UNLIKELY(!index->table->comp)) {
return(rec_get_n_fields_old(rec));
}
switch (rec_get_status(rec)) {
@@ -440,7 +440,7 @@ rec_get_n_owned(
/*============*/
/* out: number of owned records */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
ulint ret;
@@ -461,7 +461,7 @@ void
rec_set_n_owned(
/*============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint n_owned) /* in: the number of owned */
{
ut_ad(rec);
@@ -480,7 +480,7 @@ rec_get_info_bits(
/*==============*/
/* out: info bits */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
ulint ret;
@@ -501,7 +501,7 @@ void
rec_set_info_bits(
/*==============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint bits) /* in: info bits */
{
ut_ad(rec);
@@ -537,14 +537,14 @@ rec_get_info_and_status_bits(
/*=========================*/
/* out: info bits */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
ulint bits;
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
#endif
- if (comp) {
+ if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
} else {
bits = rec_get_info_bits(rec, FALSE);
@@ -560,7 +560,7 @@ void
rec_set_info_and_status_bits(
/*=========================*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint bits) /* in: info bits */
{
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
@@ -578,19 +578,22 @@ rec_set_info_and_status_bits(
/**********************************************************
The following function tells if record is delete marked. */
UNIV_INLINE
-ibool
+ulint
rec_get_deleted_flag(
/*=================*/
- /* out: TRUE if delete marked */
+ /* out: nonzero if delete marked */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
- if (REC_INFO_DELETED_FLAG & rec_get_info_bits(rec, comp)) {
-
- return(TRUE);
+ if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
+ return(UNIV_UNLIKELY(rec_get_bit_field_1(rec,
+ REC_NEW_INFO_BITS, REC_INFO_DELETED_FLAG,
+ REC_INFO_BITS_SHIFT)));
+ } else {
+ return(UNIV_UNLIKELY(rec_get_bit_field_1(rec,
+ REC_OLD_INFO_BITS, REC_INFO_DELETED_FLAG,
+ REC_INFO_BITS_SHIFT)));
}
-
- return(FALSE);
}
/**********************************************************
@@ -600,24 +603,20 @@ void
rec_set_deleted_flag(
/*=================*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
- ibool flag) /* in: TRUE if delete marked */
+ ulint comp, /* in: nonzero=compact page format */
+ ulint flag) /* in: nonzero if delete marked */
{
- ulint old_val;
- ulint new_val;
-
- ut_ad(TRUE == 1);
- ut_ad(flag <= TRUE);
+ ulint val;
- old_val = rec_get_info_bits(rec, comp);
+ val = rec_get_info_bits(rec, comp);
if (flag) {
- new_val = REC_INFO_DELETED_FLAG | old_val;
+ val |= REC_INFO_DELETED_FLAG;
} else {
- new_val = ~REC_INFO_DELETED_FLAG & old_val;
+ val &= ~REC_INFO_DELETED_FLAG;
}
- rec_set_info_bits(rec, comp, new_val);
+ rec_set_info_bits(rec, comp, val);
}
/**********************************************************
@@ -633,26 +632,6 @@ rec_get_node_ptr_flag(
}
/**********************************************************
-The following function is used to flag a record as a node pointer. */
-UNIV_INLINE
-void
-rec_set_node_ptr_flag(
-/*=================*/
- rec_t* rec, /* in: physical record */
- ibool flag) /* in: TRUE if the record is a node pointer */
-{
- ulint status;
- ut_ad(flag <= TRUE);
- ut_ad(REC_STATUS_NODE_PTR >= rec_get_status(rec));
- if (flag) {
- status = REC_STATUS_NODE_PTR;
- } else {
- status = REC_STATUS_ORDINARY;
- }
- rec_set_status(rec, status);
-}
-
-/**********************************************************
The following function is used to get the order number of the record in the
heap of the index page. */
UNIV_INLINE
@@ -661,7 +640,7 @@ rec_get_heap_no(
/*=============*/
/* out: heap order number */
rec_t* rec, /* in: physical record */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
ulint ret;
@@ -682,7 +661,7 @@ void
rec_set_heap_no(
/*=============*/
rec_t* rec, /* in: physical record */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
ulint heap_no)/* in: the heap number */
{
ut_ad(heap_no <= REC_MAX_HEAP_NO);
@@ -843,7 +822,7 @@ rec_offs_validate(
{
ulint i = rec_offs_n_fields(offsets);
ulint last = ULINT_MAX;
- ibool comp = (*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0;
+ ulint comp = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
if (rec) {
ut_ad((ulint) rec == offsets[2]);
@@ -907,7 +886,7 @@ rec_offs_make_valid(
/****************************************************************
The following function is used to get a pointer to the nth
-data field in an old-style record. */
+data field in a record. */
UNIV_INLINE
byte*
rec_get_nth_field(
@@ -926,7 +905,7 @@ rec_get_nth_field(
ut_ad(n < rec_offs_n_fields(offsets));
ut_ad(len);
- if (n == 0) {
+ if (UNIV_UNLIKELY(n == 0)) {
field = rec;
} else {
field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
@@ -949,43 +928,30 @@ rec_get_nth_field(
Determine if the offsets are for a record in the new
compact format. */
UNIV_INLINE
-ibool
+ulint
rec_offs_comp(
/*==========*/
- /* out: TRUE if compact format */
+ /* out: nonzero if compact format */
const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ut_ad(rec_offs_validate(NULL, NULL, offsets));
- return((*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0);
+ return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
}
/**********************************************************
-Returns TRUE if the nth field of rec is SQL NULL. */
-UNIV_INLINE
-ibool
-rec_offs_nth_null(
-/*==============*/
- /* out: TRUE if SQL NULL */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n) /* in: nth field */
-{
- ut_ad(rec_offs_validate(NULL, NULL, offsets));
- ut_ad(n < rec_offs_n_fields(offsets));
- return((rec_offs_base(offsets)[1 + n] & REC_OFFS_SQL_NULL) != 0);
-}
-/**********************************************************
-Returns TRUE if the extern bit is set in nth field of rec. */
+Returns nonzero if the extern bit is set in nth field of rec. */
UNIV_INLINE
-ibool
+ulint
rec_offs_nth_extern(
/*================*/
- /* out: TRUE if externally stored */
+ /* out: nonzero if externally stored */
const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint n) /* in: nth field */
{
ut_ad(rec_offs_validate(NULL, NULL, offsets));
ut_ad(n < rec_offs_n_fields(offsets));
- return((rec_offs_base(offsets)[1 + n] & REC_OFFS_EXTERNAL) != 0);
+ return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
+ & REC_OFFS_EXTERNAL));
}
/**********************************************************
@@ -1037,7 +1003,7 @@ rec_set_nth_field_extern_bit(
where rec is, or NULL; in the NULL case
we do not write to log about the change */
{
- if (index->table->comp) {
+ if (UNIV_LIKELY(index->table->comp)) {
rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
} else {
rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
@@ -1048,7 +1014,7 @@ rec_set_nth_field_extern_bit(
Returns the offset of n - 1th field end if the record is stored in the 1-byte
offsets form. If the field is SQL null, the flag is ORed in the returned
value. This function and the 2-byte counterpart are defined here because the
-C-compilerwas not able to sum negative and positive constant offsets, and
+C-compiler was not able to sum negative and positive constant offsets, and
warned of constant arithmetic overflow within the compiler. */
UNIV_INLINE
ulint
@@ -1452,7 +1418,7 @@ rec_get_converted_size(
? dict_index_get_n_unique_in_tree(index) + 1
: dict_index_get_n_fields(index)));
- if (index->table->comp) {
+ if (UNIV_LIKELY(index->table->comp)) {
return(rec_get_converted_size_new(index, dtuple));
}
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index e44d689b88b..4e6ff73b0f8 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -110,7 +110,7 @@ row_mysql_store_col_in_innobase_format(
necessarily the length of the actual
payload data; if the column is a true
VARCHAR then this is irrelevant */
- ibool comp); /* in: TRUE = compact format */
+ ulint comp); /* in: nonzero=compact format */
/********************************************************************
Handles user errors and lock waits detected by the database engine. */
@@ -172,14 +172,6 @@ row_lock_table_autoinc_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in the MySQL
table handle */
/*************************************************************************
-Unlocks all table locks explicitly requested by trx (with LOCK TABLES,
-lock type LOCK_TABLE_EXP). */
-
-void
-row_unlock_tables_for_mysql(
-/*========================*/
- trx_t* trx); /* in: transaction */
-/*************************************************************************
Sets a table lock on the table mentioned in prebuilt. */
int
@@ -190,9 +182,10 @@ row_lock_table_for_mysql(
table handle */
dict_table_t* table, /* in: table to lock, or NULL
if prebuilt->table should be
- locked as LOCK_TABLE_EXP |
+ locked as
prebuilt->select_lock_type */
- ulint mode); /* in: lock mode of table */
+ ulint mode); /* in: lock mode of table
+ (ignored if table==NULL) */
/*************************************************************************
Does an insert for MySQL. */
@@ -250,17 +243,27 @@ row_update_for_mysql(
the MySQL format */
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */
-
/*************************************************************************
-Does an unlock of a row for MySQL. */
+This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
+calling this function we must use trx_reset_new_rec_lock_info() and
+trx_register_new_rec_lock() to store the information which new record locks
+really were set. This function removes a newly set lock under prebuilt->pcur,
+and also under prebuilt->clust_pcur. Currently, this is only used and tested
+in the case of an UPDATE or a DELETE statement, where the row lock is of the
+LOCK_X type.
+Thus, this implements a 'mini-rollback' that releases the latest record
+locks we set. */
int
row_unlock_for_mysql(
/*=================*/
/* out: error code or DB_SUCCESS */
- row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
+ row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
handle */
-
+ ibool has_latches_on_recs);/* TRUE if called so that we have
+ the latches on the records under pcur
+ and clust_pcur, and we do not need to
+ reposition the cursors. */
/*************************************************************************
Creates an query graph node of 'update' type to be used in the MySQL
interface. */
@@ -599,6 +602,8 @@ struct row_prebuilt_struct {
that was decided in ha_innodb.cc,
::store_lock(), ::external_lock(),
etc. */
+ ulint mysql_prefix_len;/* byte offset of the end of
+ the last requested column */
ulint mysql_row_len; /* length in bytes of a row in the
MySQL format */
ulint n_rows_fetched; /* number of rows fetched after
diff --git a/innobase/include/row0sel.ic b/innobase/include/row0sel.ic
index 595cea1138b..600c6204571 100644
--- a/innobase/include/row0sel.ic
+++ b/innobase/include/row0sel.ic
@@ -75,7 +75,7 @@ open_step(
}
}
- if (err != DB_SUCCESS) {
+ if (UNIV_EXPECT(err, DB_SUCCESS) != DB_SUCCESS) {
/* SQL error detected */
fprintf(stderr, "SQL error %lu\n", (ulong) err);
diff --git a/innobase/include/row0upd.ic b/innobase/include/row0upd.ic
index e2d81a39cfa..acbb11aa1c7 100644
--- a/innobase/include/row0upd.ic
+++ b/innobase/include/row0upd.ic
@@ -83,7 +83,7 @@ upd_field_set_field_no(
{
upd_field->field_no = field_no;
- if (field_no >= dict_index_get_n_fields(index)) {
+ if (UNIV_UNLIKELY(field_no >= dict_index_get_n_fields(index))) {
fprintf(stderr,
"InnoDB: Error: trying to access field %lu in ",
(ulong) field_no);
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 6e4241965c1..116ae7b6438 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -182,6 +182,7 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
#define kernel_mutex (*kernel_mutex_temp)
#define SRV_MAX_N_IO_THREADS 100
+#define SRV_CONCURRENCY_THRESHOLD 20
/* Array of English strings describing the current state of an
i/o handler thread */
diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic
index 3a92100ba01..b1ae636010a 100644
--- a/innobase/include/sync0rw.ic
+++ b/innobase/include/sync0rw.ic
@@ -138,7 +138,7 @@ rw_lock_s_lock_low(
#endif /* UNIV_SYNC_DEBUG */
/* Check if the writer field is free */
- if (lock->writer == RW_LOCK_NOT_LOCKED) {
+ if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) {
/* Set the shared lock by incrementing the reader count */
lock->reader_count++;
@@ -243,7 +243,7 @@ rw_lock_s_lock_func(
mutex_enter(rw_lock_get_mutex(lock));
- if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
+ if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
mutex_exit(rw_lock_get_mutex(lock));
return; /* Success */
@@ -307,21 +307,18 @@ rw_lock_x_lock_func_nowait(
const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */
{
- ibool success = FALSE;
-
+ ibool success = FALSE;
+ os_thread_id_t curr_thread = os_thread_get_curr_id();
mutex_enter(rw_lock_get_mutex(lock));
- if ((rw_lock_get_reader_count(lock) == 0)
- && ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)
- || ((rw_lock_get_writer(lock) == RW_LOCK_EX)
- && (lock->pass == 0)
- && os_thread_eq(lock->writer_thread,
- os_thread_get_curr_id())))) {
-
+ if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) {
+ } else if (UNIV_LIKELY(rw_lock_get_writer(lock)
+ == RW_LOCK_NOT_LOCKED)) {
rw_lock_set_writer(lock, RW_LOCK_EX);
- lock->writer_thread = os_thread_get_curr_id();
- lock->writer_count++;
+ lock->writer_thread = curr_thread;
lock->pass = 0;
+ relock:
+ lock->writer_count++;
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
@@ -331,6 +328,10 @@ rw_lock_x_lock_func_nowait(
lock->last_x_line = line;
success = TRUE;
+ } else if (rw_lock_get_writer(lock) == RW_LOCK_EX
+ && lock->pass == 0
+ && os_thread_eq(lock->writer_thread, curr_thread)) {
+ goto relock;
}
mutex_exit(rw_lock_get_mutex(lock));
@@ -361,7 +362,7 @@ rw_lock_s_unlock_func(
/* Reset the shared lock by decrementing the reader count */
- ut_a(lock->reader_count > 0);
+ ut_ad(lock->reader_count > 0);
lock->reader_count--;
#ifdef UNIV_SYNC_DEBUG
@@ -371,7 +372,8 @@ rw_lock_s_unlock_func(
/* If there may be waiters and this was the last s-lock,
signal the object */
- if (lock->waiters && (lock->reader_count == 0)) {
+ if (UNIV_UNLIKELY(lock->waiters)
+ && lock->reader_count == 0) {
sg = TRUE;
rw_lock_set_waiters(lock, 0);
@@ -379,7 +381,7 @@ rw_lock_s_unlock_func(
mutex_exit(mutex);
- if (sg == TRUE) {
+ if (UNIV_UNLIKELY(sg)) {
sync_array_signal_object(sync_primary_wait_array, lock);
}
@@ -450,7 +452,8 @@ rw_lock_x_unlock_func(
#endif
/* If there may be waiters, signal the lock */
- if (lock->waiters && (lock->writer_count == 0)) {
+ if (UNIV_UNLIKELY(lock->waiters)
+ && lock->writer_count == 0) {
sg = TRUE;
rw_lock_set_waiters(lock, 0);
@@ -458,7 +461,7 @@ rw_lock_x_unlock_func(
mutex_exit(&(lock->mutex));
- if (sg == TRUE) {
+ if (UNIV_UNLIKELY(sg)) {
sync_array_signal_object(sync_primary_wait_array, lock);
}
diff --git a/innobase/include/trx0rseg.ic b/innobase/include/trx0rseg.ic
index 35e927f5e79..c9ac50ebf16 100644
--- a/innobase/include/trx0rseg.ic
+++ b/innobase/include/trx0rseg.ic
@@ -65,7 +65,7 @@ trx_rsegf_get_nth_undo(
ulint n, /* in: index of slot */
mtr_t* mtr) /* in: mtr */
{
- if (n >= TRX_RSEG_N_SLOTS) {
+ if (UNIV_UNLIKELY(n >= TRX_RSEG_N_SLOTS)) {
fprintf(stderr,
"InnoDB: Error: trying to get slot %lu of rseg\n", (unsigned long) n);
ut_error;
@@ -86,7 +86,7 @@ trx_rsegf_set_nth_undo(
ulint page_no,/* in: page number of the undo log segment */
mtr_t* mtr) /* in: mtr */
{
- if (n >= TRX_RSEG_N_SLOTS) {
+ if (UNIV_UNLIKELY(n >= TRX_RSEG_N_SLOTS)) {
fprintf(stderr,
"InnoDB: Error: trying to set slot %lu of rseg\n", (unsigned long) n);
ut_error;
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index d46613c3a68..146730d46f8 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -16,10 +16,39 @@ Created 3/26/1996 Heikki Tuuri
#include "que0types.h"
#include "mem0mem.h"
#include "read0types.h"
+#include "dict0types.h"
#include "trx0xa.h"
extern ulint trx_n_mysql_transactions;
+/*****************************************************************
+Resets the new record lock info in a transaction struct. */
+UNIV_INLINE
+void
+trx_reset_new_rec_lock_info(
+/*========================*/
+ trx_t* trx); /* in: transaction struct */
+/*****************************************************************
+Registers that we have set a new record lock on an index. We only have space
+to store 2 indexes! If this is called to store more than 2 indexes after
+trx_reset_new_rec_lock_info(), then this function does nothing. */
+UNIV_INLINE
+void
+trx_register_new_rec_lock(
+/*======================*/
+ trx_t* trx, /* in: transaction struct */
+ dict_index_t* index); /* in: trx sets a new record lock on this
+ index */
+/*****************************************************************
+Checks if trx has set a new record lock on an index. */
+UNIV_INLINE
+ibool
+trx_new_rec_locks_contain(
+/*======================*/
+ /* out: TRUE if trx has set a new record lock
+ on index */
+ trx_t* trx, /* in: transaction struct */
+ dict_index_t* index); /* in: index */
/************************************************************************
Releases the search latch if trx has reserved it. */
@@ -312,6 +341,19 @@ trx_print(
FILE* f, /* in: output stream */
trx_t* trx); /* in: transaction */
+#ifndef UNIV_HOTBACKUP
+/**************************************************************************
+Determines if the currently running transaction has been interrupted. */
+
+ibool
+trx_is_interrupted(
+/*===============*/
+ /* out: TRUE if interrupted */
+ trx_t* trx); /* in: transaction */
+#else /* !UNIV_HOTBACKUP */
+#define trx_is_interrupted(trx) FALSE
+#endif /* !UNIV_HOTBACKUP */
+
/* Signal to a transaction */
struct trx_sig_struct{
@@ -482,15 +524,18 @@ struct trx_struct{
lock_t* auto_inc_lock; /* possible auto-inc lock reserved by
the transaction; note that it is also
in the lock list trx_locks */
- ibool trx_create_lock;/* this is TRUE if we have created a
- new lock for a record accessed */
- ulint n_lock_table_exp;/* number of explicit table locks
- (LOCK TABLES) reserved by the
- transaction, stored in trx_locks */
- ulint n_lock_table_transactional;
- /* number of transactional table locks
- (LOCK TABLES..WHERE ENGINE) reserved by
- the transaction, stored in trx_locks */
+ dict_index_t* new_rec_locks[2];/* these are normally NULL; if
+ srv_locks_unsafe_for_binlog is TRUE,
+ in a cursor search, if we set a new
+ record lock on an index, this is set
+ to point to the index; this is
+ used in releasing the locks under the
+ cursors if we are performing an UPDATE
+ and we determine after retrieving
+ the row that it does not need to be
+ locked; thus, these can be used to
+ implement a 'mini-rollback' that
+ releases the latest record locks */
UT_LIST_NODE_T(trx_t)
trx_list; /* list of transactions */
UT_LIST_NODE_T(trx_t)
diff --git a/innobase/include/trx0trx.ic b/innobase/include/trx0trx.ic
index 78e5acda148..54cf2ff331f 100644
--- a/innobase/include/trx0trx.ic
+++ b/innobase/include/trx0trx.ic
@@ -39,4 +39,60 @@ trx_start_if_not_started_low(
}
}
+/*****************************************************************
+Resets the new record lock info in a transaction struct. */
+UNIV_INLINE
+void
+trx_reset_new_rec_lock_info(
+/*========================*/
+ trx_t* trx) /* in: transaction struct */
+{
+ trx->new_rec_locks[0] = NULL;
+ trx->new_rec_locks[1] = NULL;
+}
+
+/*****************************************************************
+Registers that we have set a new record lock on an index. We only have space
+to store 2 indexes! If this is called to store more than 2 indexes after
+trx_reset_new_rec_lock_info(), then this function does nothing. */
+UNIV_INLINE
+void
+trx_register_new_rec_lock(
+/*======================*/
+ trx_t* trx, /* in: transaction struct */
+ dict_index_t* index) /* in: trx sets a new record lock on this
+ index */
+{
+ if (trx->new_rec_locks[0] == NULL) {
+ trx->new_rec_locks[0] = index;
+
+ return;
+ }
+
+ if (trx->new_rec_locks[0] == index) {
+ return;
+ }
+
+ if (trx->new_rec_locks[1] != NULL) {
+
+ return;
+ }
+
+ trx->new_rec_locks[1] = index;
+}
+
+/*****************************************************************
+Checks if trx has set a new record lock on an index. */
+UNIV_INLINE
+ibool
+trx_new_rec_locks_contain(
+/*======================*/
+ /* out: TRUE if trx has set a new record lock
+ on index */
+ trx_t* trx, /* in: transaction struct */
+ dict_index_t* index) /* in: index */
+{
+ return(trx->new_rec_locks[0] == index
+ || trx->new_rec_locks[1] == index);
+}
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index 8158c198e21..132ac9e18c5 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -181,7 +181,7 @@ management to ensure correct alignment for doubles etc. */
/* Another basic type we use is unsigned long integer which should be equal to
the word size of the machine, that is on a 32-bit platform 32 bits, and on a
64-bit platform 64 bits. We also give the printf format for the type as a
-macro PRULINT. */
+macro ULINTPF. */
#ifdef _WIN64
typedef unsigned __int64 ulint;
@@ -243,6 +243,30 @@ 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)
+/* 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 */
+# define UNIV_LIKELY_NULL(ptr) __builtin_expect((ulint) ptr, 0)
+/* Minimize cache-miss latency by moving data at addr into a cache before
+it is read. */
+# define UNIV_PREFETCH_R(addr) __builtin_prefetch(addr, 0, 3)
+/* Minimize cache-miss latency by moving data at addr into a cache before
+it is read or written. */
+# define UNIV_PREFETCH_RW(addr) __builtin_prefetch(addr, 1, 3)
+#else
+/* Dummy versions of the macros */
+# define UNIV_EXPECT(expr,value) (expr)
+# define UNIV_LIKELY_NULL(expr) (expr)
+# define UNIV_PREFETCH_R(addr) ((void) 0)
+# define UNIV_PREFETCH_RW(addr) ((void) 0)
+#endif
+/* Tell the compiler that cond is likely to hold */
+#define UNIV_LIKELY(cond) UNIV_EXPECT(cond, TRUE)
+/* Tell the compiler that cond is unlikely to hold */
+#define UNIV_UNLIKELY(cond) UNIV_EXPECT(cond, FALSE)
+
#include <stdio.h>
#include "ut0dbg.h"
#include "ut0ut.h"
diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h
index 5f30a894874..bc3f852626a 100644
--- a/innobase/include/ut0dbg.h
+++ b/innobase/include/ut0dbg.h
@@ -13,74 +13,75 @@ Created 1/30/1994 Heikki Tuuri
#include <stdlib.h>
#include "os0thread.h"
+#if defined(__GNUC__) && (__GNUC__ > 2)
+# define UT_DBG_FAIL(EXPR) UNIV_UNLIKELY(!((ulint)(EXPR)))
+#else
extern ulint ut_dbg_zero; /* This is used to eliminate
compiler warnings */
+# define UT_DBG_FAIL(EXPR) !((ulint)(EXPR) + ut_dbg_zero)
+#endif
+
+/*****************************************************************
+Report a failed assertion. */
+
+void
+ut_dbg_assertion_failed(
+/*====================*/
+ const char* expr, /* in: the failed assertion */
+ const char* file, /* in: source file containing the assertion */
+ ulint line); /* in: line number of the assertion */
+
+#ifdef __NETWARE__
+/* Flag for ignoring further assertion failures.
+On NetWare, have a graceful exit rather than a segfault to avoid abends. */
+extern ibool panic_shutdown;
+/* Abort the execution. */
+void ut_dbg_panic(void);
+# define UT_DBG_PANIC ut_dbg_panic()
+/* Stop threads in ut_a(). */
+# define UT_DBG_STOP while (0) /* We do not do this on NetWare */
+#else /* __NETWARE__ */
+/* Flag for indicating that all threads should stop. This will be set
+by ut_dbg_assertion_failed(). */
extern ibool ut_dbg_stop_threads;
+/* A null pointer that will be dereferenced to trigger a memory trap */
extern ulint* ut_dbg_null_ptr;
-extern const char* ut_dbg_msg_assert_fail;
-extern const char* ut_dbg_msg_trap;
-extern const char* ut_dbg_msg_stop;
-/* Have a graceful exit on NetWare rather than a segfault to avoid abends */
-#ifdef __NETWARE__
-extern ibool panic_shutdown;
-#define ut_a(EXPR) do {\
- if (!((ulint)(EXPR) + ut_dbg_zero)) {\
- ut_print_timestamp(stderr);\
- fprintf(stderr, ut_dbg_msg_assert_fail,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__,\
- (ulint)__LINE__);\
- fputs("InnoDB: Failing assertion: " #EXPR "\n", stderr);\
- fputs(ut_dbg_msg_trap, stderr);\
- ut_dbg_stop_threads = TRUE;\
- if (ut_dbg_stop_threads) {\
- fprintf(stderr, ut_dbg_msg_stop,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__, (ulint)__LINE__);\
- }\
- if(!panic_shutdown){\
- panic_shutdown = TRUE;\
- innobase_shutdown_for_mysql();}\
- exit(1);\
- }\
-} while (0)
-#define ut_error do {\
- ut_print_timestamp(stderr);\
- fprintf(stderr, ut_dbg_msg_assert_fail,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__, (ulint)__LINE__);\
- fprintf(stderr, ut_dbg_msg_trap);\
- ut_dbg_stop_threads = TRUE;\
- if(!panic_shutdown){panic_shutdown = TRUE;\
- innobase_shutdown_for_mysql();}\
-} while (0)
-#else
-#define ut_a(EXPR) do {\
- if (!((ulint)(EXPR) + ut_dbg_zero)) {\
- ut_print_timestamp(stderr);\
- fprintf(stderr, ut_dbg_msg_assert_fail,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__,\
- (ulint)__LINE__);\
- fputs("InnoDB: Failing assertion: " #EXPR "\n", stderr);\
- fputs(ut_dbg_msg_trap, stderr);\
- ut_dbg_stop_threads = TRUE;\
- if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL;\
- }\
- if (ut_dbg_stop_threads) {\
- fprintf(stderr, ut_dbg_msg_stop,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__, (ulint)__LINE__);\
- os_thread_sleep(1000000000);\
- }\
+/*****************************************************************
+Stop a thread after assertion failure. */
+
+void
+ut_dbg_stop_thread(
+/*===============*/
+ const char* file,
+ ulint line);
+
+/* Abort the execution. */
+# define UT_DBG_PANIC \
+ if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL
+/* Stop threads in ut_a(). */
+# define UT_DBG_STOP do \
+ if (UNIV_UNLIKELY(ut_dbg_stop_threads)) { \
+ ut_dbg_stop_thread(__FILE__, (ulint) __LINE__); \
+ } while (0)
+#endif /* __NETWARE__ */
+
+/* Abort execution if EXPR does not evaluate to nonzero. */
+#define ut_a(EXPR) do { \
+ if (UT_DBG_FAIL(EXPR)) { \
+ ut_dbg_assertion_failed(#EXPR, \
+ __FILE__, (ulint) __LINE__); \
+ UT_DBG_PANIC; \
+ } \
+ UT_DBG_STOP; \
} while (0)
-#define ut_error do {\
- ut_print_timestamp(stderr);\
- fprintf(stderr, ut_dbg_msg_assert_fail,\
- os_thread_pf(os_thread_get_curr_id()), __FILE__, (ulint)__LINE__);\
- fprintf(stderr, ut_dbg_msg_trap);\
- ut_dbg_stop_threads = TRUE;\
- if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL;\
+/* Abort execution. */
+#define ut_error do { \
+ ut_dbg_assertion_failed(0, __FILE__, (ulint) __LINE__); \
+ UT_DBG_PANIC; \
} while (0)
-#endif
#ifdef UNIV_DEBUG
#define ut_ad(EXPR) ut_a(EXPR)
diff --git a/innobase/include/ut0rnd.ic b/innobase/include/ut0rnd.ic
index 06d7012f60b..d2ab087d491 100644
--- a/innobase/include/ut0rnd.ic
+++ b/innobase/include/ut0rnd.ic
@@ -207,12 +207,12 @@ ut_fold_binary(
const byte* str, /* in: string of bytes */
ulint len) /* in: length */
{
- ulint i;
- ulint fold = 0;
+ const byte* str_end = str + len;
+ ulint fold = 0;
ut_ad(str);
- for (i = 0; i < len; i++) {
+ while (str < str_end) {
fold = ut_fold_ulint_pair(fold, (ulint)(*str));
str++;
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 73ecc717e0e..280c4871ee9 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -292,7 +292,25 @@ waiting, in its lock queue. Solution: We can copy the locks as gap type
locks, so that also the waiting locks are transformed to granted gap type
locks on the inserted record. */
+/* LOCK COMPATIBILITY MATRIX
+ * IS IX S X AI
+ * IS + + + - +
+ * IX + + - - +
+ * S + - + - -
+ * X - - - - -
+ * AI + + - - -
+ *
+ * Note that for rows, InnoDB only acquires S or X locks.
+ * For tables, InnoDB normally acquires IS or IX locks.
+ * S or X table locks are only acquired for LOCK TABLES.
+ * Auto-increment (AI) locks are needed because of
+ * statement-level MySQL binlog.
+ * See also lock_mode_compatible().
+ */
+
+#ifdef UNIV_DEBUG
ibool lock_print_waits = FALSE;
+#endif /* UNIV_DEBUG */
/* The lock system */
lock_sys_t* lock_sys = NULL;
@@ -348,17 +366,26 @@ static
ibool
lock_deadlock_occurs(
/*=================*/
- /* out: TRUE if a deadlock was detected */
+ /* out: TRUE if a deadlock was detected and we
+ chose trx as a victim; FALSE if no deadlock, or
+ there was a deadlock, but we chose other
+ transaction(s) as victim(s) */
lock_t* lock, /* in: lock the transaction is requesting */
trx_t* trx); /* in: transaction */
/************************************************************************
Looks recursively for a deadlock. */
static
-ibool
+ulint
lock_deadlock_recursive(
/*====================*/
- /* out: TRUE if a deadlock was detected
- or the calculation took too long */
+ /* out: 0 if no deadlock found,
+ LOCK_VICTIM_IS_START if there was a deadlock
+ and we chose 'start' as the victim,
+ LOCK_VICTIM_IS_OTHER if a deadlock
+ was found and we chose some other trx as a
+ victim: we must do the search again in this
+ last case because there may be another
+ deadlock! */
trx_t* start, /* in: recursion starting point */
trx_t* trx, /* in: a transaction waiting for a lock */
lock_t* wait_lock, /* in: the lock trx is waiting to be granted */
@@ -492,12 +519,7 @@ lock_clust_rec_cons_read_sees(
trx_id = row_get_rec_trx_id(rec, index, offsets);
- if (read_view_sees_trx_id(view, trx_id)) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(read_view_sees_trx_id(view, trx_id));
}
/*************************************************************************
@@ -934,7 +956,7 @@ lock_rec_has_to_wait(
cause waits */
if ((lock_is_on_supremum || (type_mode & LOCK_GAP))
- && !(type_mode & LOCK_INSERT_INTENTION)) {
+ && !(type_mode & LOCK_INSERT_INTENTION)) {
/* Gap type locks without LOCK_INSERT_INTENTION flag
do not need to wait for anything. This is because
@@ -1261,7 +1283,6 @@ lock_rec_get_next(
/*==============*/
/* out: next lock, NULL if none exists */
rec_t* rec, /* in: record on a page */
- ibool comp, /* in: TRUE=compact page format */
lock_t* lock) /* in: lock */
{
#ifdef UNIV_SYNC_DEBUG
@@ -1269,19 +1290,19 @@ lock_rec_get_next(
#endif /* UNIV_SYNC_DEBUG */
ut_ad(lock_get_type(lock) == LOCK_REC);
- for (;;) {
- lock = lock_rec_get_next_on_page(lock);
-
- if (lock == NULL) {
-
- return(NULL);
- }
-
- if (lock_rec_get_nth_bit(lock, rec_get_heap_no(rec, comp))) {
-
- return(lock);
- }
+ if (page_rec_is_comp(rec)) {
+ do {
+ lock = lock_rec_get_next_on_page(lock);
+ } while (lock && !lock_rec_get_nth_bit(lock,
+ rec_get_heap_no(rec, TRUE)));
+ } else {
+ do {
+ lock = lock_rec_get_next_on_page(lock);
+ } while (lock && !lock_rec_get_nth_bit(lock,
+ rec_get_heap_no(rec, FALSE)));
}
+
+ return(lock);
}
/*************************************************************************
@@ -1294,22 +1315,18 @@ lock_rec_get_first(
rec_t* rec) /* in: record on a page */
{
lock_t* lock;
- ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
lock = lock_rec_get_first_on_page(rec);
- comp = page_is_comp(buf_frame_align(rec));
-
- while (lock) {
- if (lock_rec_get_nth_bit(lock, rec_get_heap_no(rec, comp))) {
+ if (UNIV_LIKELY_NULL(lock)) {
+ ulint heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
- break;
+ while (lock && !lock_rec_get_nth_bit(lock, heap_no)) {
+ lock = lock_rec_get_next_on_page(lock);
}
-
- lock = lock_rec_get_next_on_page(lock);
}
return(lock);
@@ -1471,7 +1488,6 @@ lock_rec_has_expl(
for a supremum record we regard this always a gap
type request */
rec_t* rec, /* in: record */
- ibool comp, /* in: TRUE=compact page format */
trx_t* trx) /* in: transaction */
{
lock_t* lock;
@@ -1501,7 +1517,7 @@ lock_rec_has_expl(
return(lock);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
return(NULL);
@@ -1520,7 +1536,6 @@ lock_rec_other_has_expl_req(
ulint wait, /* in: LOCK_WAIT if also waiting locks are
taken into account, or 0 if not */
rec_t* rec, /* in: record to look at */
- ibool comp, /* in: TRUE=compact record format */
trx_t* trx) /* in: transaction, or NULL if requests by all
transactions are taken into account */
{
@@ -1545,7 +1560,7 @@ lock_rec_other_has_expl_req(
return(lock);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
return(NULL);
@@ -1566,13 +1581,11 @@ lock_rec_other_has_conflicting(
trx_t* trx) /* in: our transaction */
{
lock_t* lock;
- ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
lock = lock_rec_get_first(rec);
- comp = page_is_comp(buf_frame_align(rec));
while (lock) {
if (lock_rec_has_to_wait(trx, mode, lock,
@@ -1581,7 +1594,7 @@ lock_rec_other_has_conflicting(
return(lock);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
return(NULL);
@@ -1607,7 +1620,7 @@ lock_rec_find_similar_on_page(
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- heap_no = rec_get_heap_no(rec, page_is_comp(buf_frame_align(rec)));
+ heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
lock = lock_rec_get_first_on_page(rec);
while (lock != NULL) {
@@ -1709,6 +1722,8 @@ lock_rec_create(
page_no = buf_frame_get_page_no(page);
heap_no = rec_get_heap_no(rec, page_is_comp(page));
+ ut_ad(!!page_is_comp(page) == index->table->comp);
+
/* If rec is the supremum record, then we reset the gap and
LOCK_REC_NOT_GAP bits, as all locks on the supremum are
automatically of the gap type */
@@ -1725,7 +1740,7 @@ lock_rec_create(
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
- if (lock == NULL) {
+ if (UNIV_UNLIKELY(lock == NULL)) {
return(NULL);
}
@@ -1750,10 +1765,7 @@ lock_rec_create(
lock_rec_set_nth_bit(lock, heap_no);
HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
- lock_rec_fold(space, page_no), lock);
- /* Note that we have create a new lock */
- trx->trx_create_lock = TRUE;
-
+ lock_rec_fold(space, page_no), lock);
if (type_mode & LOCK_WAIT) {
lock_set_lock_and_trx_wait(lock, trx);
@@ -1826,7 +1838,7 @@ lock_rec_enqueue_waiting(
lock_reset_lock_and_trx_wait(lock);
lock_rec_reset_nth_bit(lock, rec_get_heap_no(rec,
- page_is_comp(buf_frame_align(rec))));
+ page_rec_is_comp(rec)));
return(DB_DEADLOCK);
}
@@ -1845,11 +1857,13 @@ lock_rec_enqueue_waiting(
ut_a(que_thr_stop(thr));
+#ifdef UNIV_DEBUG
if (lock_print_waits) {
fprintf(stderr, "Lock wait for trx %lu in index ",
(ulong) ut_dulint_get_low(trx->id));
ut_print_name(stderr, trx, index->name);
}
+#endif /* UNIV_DEBUG */
return(DB_LOCK_WAIT);
}
@@ -1876,7 +1890,6 @@ lock_rec_add_to_queue(
lock_t* lock;
lock_t* similar_lock = NULL;
ulint heap_no;
- page_t* page = buf_frame_align(rec);
ibool somebody_waits = FALSE;
#ifdef UNIV_SYNC_DEBUG
@@ -1885,11 +1898,11 @@ lock_rec_add_to_queue(
ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP))
|| ((type_mode & LOCK_MODE_MASK) != LOCK_S)
|| !lock_rec_other_has_expl_req(LOCK_X, 0, LOCK_WAIT,
- rec, page_is_comp(page), trx));
+ rec, trx));
ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP))
|| ((type_mode & LOCK_MODE_MASK) != LOCK_X)
|| !lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT,
- rec, page_is_comp(page), trx));
+ rec, trx));
type_mode = type_mode | LOCK_REC;
@@ -1898,7 +1911,7 @@ lock_rec_add_to_queue(
try to avoid unnecessary memory consumption of a new record lock
struct for a gap type lock */
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
ut_ad(!(type_mode & LOCK_REC_NOT_GAP));
/* There should never be LOCK_REC_NOT_GAP on a supremum
@@ -1909,7 +1922,7 @@ lock_rec_add_to_queue(
/* Look for a waiting lock request on the same record or on a gap */
- heap_no = rec_get_heap_no(rec, page_is_comp(page));
+ heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
lock = lock_rec_get_first_on_page(rec);
while (lock != NULL) {
@@ -1929,15 +1942,6 @@ lock_rec_add_to_queue(
if (similar_lock && !somebody_waits && !(type_mode & LOCK_WAIT)) {
- /* If the nth bit of a record lock is already set then we
- do not set a new lock bit, otherwice we set */
-
- if (lock_rec_get_nth_bit(similar_lock, heap_no)) {
- trx->trx_create_lock = FALSE;
- } else {
- trx->trx_create_lock = TRUE;
- }
-
lock_rec_set_nth_bit(similar_lock, heap_no);
return(similar_lock);
@@ -1984,16 +1988,19 @@ lock_rec_lock_fast(
|| mode - (LOCK_MODE_MASK & mode) == 0
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
- heap_no = rec_get_heap_no(rec, page_is_comp(buf_frame_align(rec)));
+ heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
lock = lock_rec_get_first_on_page(rec);
trx = thr_get_trx(thr);
- trx->trx_create_lock = FALSE;
if (lock == NULL) {
if (!impl) {
lock_rec_create(mode, rec, index, trx);
+
+ if (srv_locks_unsafe_for_binlog) {
+ trx_register_new_rec_lock(trx, index);
+ }
}
return(TRUE);
@@ -2005,23 +2012,22 @@ lock_rec_lock_fast(
}
if (lock->trx != trx
- || lock->type_mode != (mode | LOCK_REC)
- || lock_rec_get_n_bits(lock) <= heap_no) {
+ || lock->type_mode != (mode | LOCK_REC)
+ || lock_rec_get_n_bits(lock) <= heap_no) {
+
return(FALSE);
}
if (!impl) {
+ /* If the nth bit of the record lock is already set then we
+ do not set a new lock bit, otherwise we do set */
- /* If the nth bit of a record lock is already set then we
- do not set a new lock bit, otherwice we set */
-
- if (lock_rec_get_nth_bit(lock, heap_no)) {
- trx->trx_create_lock = FALSE;
- } else {
- trx->trx_create_lock = TRUE;
+ if (!lock_rec_get_nth_bit(lock, heap_no)) {
+ lock_rec_set_nth_bit(lock, heap_no);
+ if (srv_locks_unsafe_for_binlog) {
+ trx_register_new_rec_lock(trx, index);
+ }
}
-
- lock_rec_set_nth_bit(lock, heap_no);
}
return(TRUE);
@@ -2065,8 +2071,7 @@ lock_rec_lock_slow(
trx = thr_get_trx(thr);
- if (lock_rec_has_expl(mode, rec,
- page_is_comp(buf_frame_align(rec)), trx)) {
+ if (lock_rec_has_expl(mode, rec, trx)) {
/* The trx already has a strong enough lock on rec: do
nothing */
@@ -2078,12 +2083,19 @@ lock_rec_lock_slow(
enough already granted on the record, we have to wait. */
err = lock_rec_enqueue_waiting(mode, rec, index, thr);
+
+ if (srv_locks_unsafe_for_binlog) {
+ trx_register_new_rec_lock(trx, index);
+ }
} else {
if (!impl) {
/* Set the requested lock on the record */
lock_rec_add_to_queue(LOCK_REC | mode, rec, index,
trx);
+ if (srv_locks_unsafe_for_binlog) {
+ trx_register_new_rec_lock(trx, index);
+ }
}
err = DB_SUCCESS;
@@ -2207,16 +2219,14 @@ lock_grant(
release it at the end of the SQL statement */
lock->trx->auto_inc_lock = lock;
- } else if (lock_get_type(lock) == LOCK_TABLE_EXP ||
- lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
- ut_a(lock_get_mode(lock) == LOCK_S
- || lock_get_mode(lock) == LOCK_X);
- }
+ }
+#ifdef UNIV_DEBUG
if (lock_print_waits) {
fprintf(stderr, "Lock wait for trx %lu ends\n",
(ulong) ut_dulint_get_low(lock->trx->id));
}
+#endif /* UNIV_DEBUG */
/* If we are resolving a deadlock by choosing another transaction
as a victim, then our original transaction may not be in the
@@ -2383,14 +2393,12 @@ lock_rec_reset_and_release_wait(
{
lock_t* lock;
ulint heap_no;
- ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- comp = page_is_comp(buf_frame_align(rec));
- heap_no = rec_get_heap_no(rec, comp);
+ heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
lock = lock_rec_get_first(rec);
@@ -2401,7 +2409,7 @@ lock_rec_reset_and_release_wait(
lock_rec_reset_nth_bit(lock, heap_no);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
}
@@ -2419,23 +2427,28 @@ lock_rec_inherit_to_gap(
the locks on this record */
{
lock_t* lock;
- ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
lock = lock_rec_get_first(rec);
- comp = page_is_comp(buf_frame_align(rec));
+
+ /* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set
+ by an UPDATE or a DELETE to be inherited as gap type locks. But we
+ DO want S-locks set by a consistency constraint to be inherited also
+ then. */
while (lock != NULL) {
- if (!lock_rec_get_insert_intention(lock)) {
+ if (!lock_rec_get_insert_intention(lock)
+ && !(srv_locks_unsafe_for_binlog
+ && lock_get_mode(lock) == LOCK_X)) {
lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock)
| LOCK_GAP,
heir, lock->index, lock->trx);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
}
@@ -2452,13 +2465,11 @@ lock_rec_inherit_to_gap_if_gap_lock(
the locks on this record */
{
lock_t* lock;
- ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
lock = lock_rec_get_first(rec);
- comp = page_is_comp(buf_frame_align(rec));
while (lock != NULL) {
if (!lock_rec_get_insert_intention(lock)
@@ -2470,7 +2481,7 @@ lock_rec_inherit_to_gap_if_gap_lock(
heir, lock->index, lock->trx);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
}
@@ -2484,7 +2495,7 @@ lock_rec_move(
rec_t* receiver, /* in: record which gets locks; this record
must have no lock requests on it! */
rec_t* donator, /* in: record which gives locks */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
lock_t* lock;
ulint heap_no;
@@ -2514,7 +2525,7 @@ lock_rec_move(
lock_rec_add_to_queue(type_mode, receiver, lock->index,
lock->trx);
- lock = lock_rec_get_next(donator, comp, lock);
+ lock = lock_rec_get_next(donator, lock);
}
ut_ad(lock_rec_get_first(donator) == NULL);
@@ -2540,7 +2551,7 @@ lock_move_reorganize_page(
UT_LIST_BASE_NODE_T(lock_t) old_locks;
mem_heap_t* heap = NULL;
rec_t* sup;
- ibool comp;
+ ulint comp;
lock_mutex_enter_kernel();
@@ -2659,8 +2670,9 @@ lock_move_rec_list_end(
ulint heap_no;
rec_t* sup;
ulint type_mode;
- ibool comp;
-
+ ulint comp;
+ ut_ad(page == buf_frame_align(rec));
+
lock_mutex_enter_kernel();
/* Note: when we move locks from record to record, waiting locks
@@ -2745,7 +2757,7 @@ lock_move_rec_list_start(
page_cur_t cur2;
ulint heap_no;
ulint type_mode;
- ibool comp;
+ ulint comp;
ut_a(new_page);
@@ -2754,6 +2766,7 @@ lock_move_rec_list_start(
lock = lock_rec_get_first_on_page(page);
comp = page_is_comp(page);
ut_ad(comp == page_is_comp(new_page));
+ ut_ad(page == buf_frame_align(rec));
while (lock != NULL) {
@@ -2812,7 +2825,7 @@ lock_update_split_right(
page_t* right_page, /* in: right page */
page_t* left_page) /* in: left page */
{
- ibool comp;
+ ulint comp;
lock_mutex_enter_kernel();
comp = page_is_comp(left_page);
ut_ad(comp == page_is_comp(right_page));
@@ -2875,7 +2888,7 @@ lock_update_root_raise(
page_t* new_page, /* in: index page to which copied */
page_t* root) /* in: root page */
{
- ibool comp;
+ ulint comp;
lock_mutex_enter_kernel();
comp = page_is_comp(root);
ut_ad(comp == page_is_comp(new_page));
@@ -2898,7 +2911,7 @@ lock_update_copy_and_discard(
page_t* new_page, /* in: index page to which copied */
page_t* page) /* in: index page; NOT the root! */
{
- ibool comp;
+ ulint comp;
lock_mutex_enter_kernel();
comp = page_is_comp(page);
ut_ad(comp == page_is_comp(new_page));
@@ -2945,31 +2958,34 @@ lock_update_merge_left(
page_t* right_page) /* in: merged index page which will be
discarded */
{
- ibool comp;
+ rec_t* left_next_rec;
+ rec_t* left_supremum;
+ ulint comp;
lock_mutex_enter_kernel();
comp = page_is_comp(left_page);
ut_ad(comp == page_is_comp(right_page));
+ ut_ad(left_page == buf_frame_align(orig_pred));
- if (page_rec_get_next(orig_pred) != page_get_supremum_rec(left_page)) {
+ left_next_rec = page_rec_get_next(orig_pred);
+ left_supremum = page_get_supremum_rec(left_page);
+
+ if (UNIV_LIKELY(left_next_rec != left_supremum)) {
/* Inherit the locks on the supremum of the left page to the
first record which was moved from the right page */
- lock_rec_inherit_to_gap(page_rec_get_next(orig_pred),
- page_get_supremum_rec(left_page));
+ lock_rec_inherit_to_gap(left_next_rec, left_supremum);
/* Reset the locks on the supremum of the left page,
releasing waiting transactions */
- lock_rec_reset_and_release_wait(page_get_supremum_rec(
- left_page));
+ lock_rec_reset_and_release_wait(left_supremum);
}
/* Move the locks from the supremum of right page to the supremum
of the left page */
- lock_rec_move(page_get_supremum_rec(left_page),
- page_get_supremum_rec(right_page), comp);
+ lock_rec_move(left_supremum, page_get_supremum_rec(right_page), comp);
lock_rec_free_all_from_discard_page(right_page);
@@ -3028,7 +3044,7 @@ lock_update_discard(
lock_rec_reset_and_release_wait(rec);
- if (rec == page_get_supremum_rec(page)) {
+ if (page_rec_is_supremum(rec)) {
break;
}
@@ -3057,7 +3073,7 @@ lock_update_insert(
lock_rec_inherit_to_gap_if_gap_lock(rec, page_rec_get_next(rec));
lock_mutex_exit_kernel();
-}
+}
/*****************************************************************
Updates the lock table when a record is removed. */
@@ -3091,19 +3107,16 @@ actual record is being moved. */
void
lock_rec_store_on_page_infimum(
/*===========================*/
+ page_t* page, /* in: page containing the record */
rec_t* rec) /* in: record whose lock state is stored
on the infimum record of the same page; lock
bits are reset on the record */
{
- page_t* page;
- ibool comp;
-
- page = buf_frame_align(rec);
- comp = page_is_comp(page);
+ ut_ad(page == buf_frame_align(rec));
lock_mutex_enter_kernel();
- lock_rec_move(page_get_infimum_rec(page), rec, comp);
+ lock_rec_move(page_get_infimum_rec(page), rec, page_is_comp(page));
lock_mutex_exit_kernel();
}
@@ -3120,10 +3133,10 @@ lock_rec_restore_from_page_infimum(
whose infimum stored the lock state; lock bits are
reset on the infimum */
{
- ibool comp;
+ ulint comp;
lock_mutex_enter_kernel();
comp = page_is_comp(page);
- ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ ut_ad(!comp == !page_rec_is_comp(rec));
lock_rec_move(rec, page_get_infimum_rec(page), comp);
@@ -3316,11 +3329,11 @@ lock_deadlock_recursive(
} else {
lock_table_print(ef, start->wait_lock);
}
-
+#ifdef UNIV_DEBUG
if (lock_print_waits) {
fputs("Deadlock detected\n", stderr);
}
-
+#endif /* UNIV_DEBUG */
if (ut_dulint_cmp(wait_lock->trx->undo_no,
start->undo_no) >= 0) {
/* Our recursion starting point
@@ -3418,14 +3431,6 @@ lock_table_create(
lock->type_mode = type_mode | LOCK_TABLE;
lock->trx = trx;
- if (lock_get_type(lock) == LOCK_TABLE_EXP) {
- lock->trx->n_lock_table_exp++;
- }
-
- if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
- lock->trx->n_lock_table_transactional++;
- }
-
lock->un_member.tab_lock.table = table;
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
@@ -3462,14 +3467,6 @@ lock_table_remove_low(
trx->auto_inc_lock = NULL;
}
- if (lock_get_type(lock) == LOCK_TABLE_EXP) {
- trx->n_lock_table_exp--;
- }
-
- if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
- trx->n_lock_table_transactional--;
- }
-
UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
UT_LIST_REMOVE(un_member.tab_lock.locks, table->locks, lock);
}
@@ -3600,10 +3597,7 @@ lock_table(
/* out: DB_SUCCESS, DB_LOCK_WAIT,
DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing;
- if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL
- bits are set,
- creates an explicit table lock */
+ does nothing */
dict_table_t* table, /* in: database table in dictionary cache */
ulint mode, /* in: lock mode */
que_thr_t* thr) /* in: query thread */
@@ -3618,8 +3612,7 @@ lock_table(
return(DB_SUCCESS);
}
- ut_a(flags == 0 || flags == LOCK_TABLE_EXP ||
- flags == LOCK_TABLE_TRANSACTIONAL);
+ ut_a(flags == 0);
trx = thr_get_trx(thr);
@@ -3732,9 +3725,7 @@ lock_table_dequeue(
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- ut_a(lock_get_type(in_lock) == LOCK_TABLE ||
- lock_get_type(in_lock) == LOCK_TABLE_EXP ||
- lock_get_type(in_lock) == LOCK_TABLE_TRANSACTIONAL);
+ ut_a(lock_get_type(in_lock) == LOCK_TABLE);
lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
@@ -3838,12 +3829,6 @@ lock_release_off_kernel(
}
lock_table_dequeue(lock);
-
- if (lock_get_type(lock) == LOCK_TABLE_EXP ||
- lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
- ut_a(lock_get_mode(lock) == LOCK_S
- || lock_get_mode(lock) == LOCK_X);
- }
}
if (count == LOCK_RELEASE_KERNEL_INTERVAL) {
@@ -3863,74 +3848,6 @@ lock_release_off_kernel(
mem_heap_empty(trx->lock_heap);
ut_a(trx->auto_inc_lock == NULL);
- ut_a(trx->n_lock_table_exp == 0);
- ut_a(trx->n_lock_table_transactional == 0);
-}
-
-/*************************************************************************
-Releases table locks explicitly requested with LOCK TABLES (indicated by
-lock type LOCK_TABLE_EXP), and releases possible other transactions waiting
-because of these locks. */
-
-void
-lock_release_tables_off_kernel(
-/*===========================*/
- trx_t* trx) /* in: transaction */
-{
- dict_table_t* table;
- ulint count;
- lock_t* lock;
-
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(mutex_own(&kernel_mutex));
-#endif /* UNIV_SYNC_DEBUG */
-
- lock = UT_LIST_GET_LAST(trx->trx_locks);
-
- count = 0;
-
- while (lock != NULL) {
-
- count++;
-
- if (lock_get_type(lock) == LOCK_TABLE_EXP) {
- ut_a(lock_get_mode(lock) == LOCK_S
- || lock_get_mode(lock) == LOCK_X);
- if (trx->insert_undo || trx->update_undo) {
-
- /* The trx may have modified the table.
- We block the use of the MySQL query
- cache for all currently active
- transactions. */
-
- table = lock->un_member.tab_lock.table;
-
- table->query_cache_inv_trx_id =
- trx_sys->max_trx_id;
- }
-
- lock_table_dequeue(lock);
-
- lock = UT_LIST_GET_LAST(trx->trx_locks);
- continue;
- }
-
- if (count == LOCK_RELEASE_KERNEL_INTERVAL) {
- /* Release the kernel mutex for a while, so that we
- do not monopolize it */
-
- lock_mutex_exit_kernel();
-
- lock_mutex_enter_kernel();
-
- count = 0;
- }
-
- lock = UT_LIST_GET_PREV(trx_locks, lock);
- }
-
- ut_a(trx->n_lock_table_exp == 0);
- ut_a(trx->n_lock_table_transactional == 0);
}
/*************************************************************************
@@ -4043,15 +3960,7 @@ lock_table_print(
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- ut_a(lock_get_type(lock) == LOCK_TABLE ||
- lock_get_type(lock) == LOCK_TABLE_EXP ||
- lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL);
-
- if (lock_get_type(lock) == LOCK_TABLE_EXP) {
- fputs("EXPLICIT ", file);
- } else if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
- fputs("TRANSACTIONAL ", file);
- }
+ ut_a(lock_get_type(lock) == LOCK_TABLE);
fputs("TABLE LOCK table ", file);
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
@@ -4187,7 +4096,7 @@ lock_rec_print(
}
mtr_commit(&mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -4483,15 +4392,14 @@ lock_rec_queue_validate(
{
trx_t* impl_trx;
lock_t* lock;
- ibool comp;
ut_a(rec);
ut_ad(rec_offs_validate(rec, index, offsets));
- comp = page_is_comp(buf_frame_align(rec));
+ ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
lock_mutex_enter_kernel();
- if (page_rec_is_supremum(rec) || page_rec_is_infimum(rec)) {
+ if (!page_rec_is_user_rec(rec)) {
lock = lock_rec_get_first(rec);
@@ -4511,7 +4419,7 @@ lock_rec_queue_validate(
ut_a(lock->index == index);
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
lock_mutex_exit_kernel();
@@ -4524,10 +4432,10 @@ lock_rec_queue_validate(
impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
if (impl_trx && lock_rec_other_has_expl_req(LOCK_S, 0,
- LOCK_WAIT, rec, comp, impl_trx)) {
+ LOCK_WAIT, rec, impl_trx)) {
ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
- comp, impl_trx));
+ impl_trx));
}
}
@@ -4541,10 +4449,10 @@ lock_rec_queue_validate(
rec, index, offsets);
if (impl_trx && lock_rec_other_has_expl_req(LOCK_S, 0,
- LOCK_WAIT, rec, comp, impl_trx)) {
+ LOCK_WAIT, rec, impl_trx)) {
ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
- rec, comp, impl_trx));
+ rec, impl_trx));
}
}
@@ -4561,21 +4469,23 @@ lock_rec_queue_validate(
}
if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) {
+
+ ulint mode;
if (lock_get_mode(lock) == LOCK_S) {
- ut_a(!lock_rec_other_has_expl_req(LOCK_X,
- 0, 0, rec, comp, lock->trx));
+ mode = LOCK_X;
} else {
- ut_a(!lock_rec_other_has_expl_req(LOCK_S,
- 0, 0, rec, comp, lock->trx));
+ mode = LOCK_S;
}
+ ut_a(!lock_rec_other_has_expl_req(mode,
+ 0, 0, rec, lock->trx));
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
ut_a(lock_rec_has_to_wait_in_queue(lock));
}
- lock = lock_rec_get_next(rec, comp, lock);
+ lock = lock_rec_get_next(rec, lock);
}
lock_mutex_exit_kernel();
@@ -4673,7 +4583,7 @@ function_exit:
mtr_commit(&mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(TRUE);
@@ -4859,7 +4769,7 @@ lock_rec_insert_check_and_lock(
offsets = rec_get_offsets(next_rec, index, offsets_,
ULINT_UNDEFINED, &heap);
ut_ad(lock_rec_queue_validate(next_rec, index, offsets));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -4887,7 +4797,7 @@ lock_rec_convert_impl_to_expl(
#endif /* UNIV_SYNC_DEBUG */
ut_ad(page_rec_is_user_rec(rec));
ut_ad(rec_offs_validate(rec, index, offsets));
- ut_ad(page_is_comp(buf_frame_align(rec)) == index->table->comp);
+ ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
if (index->type & DICT_CLUSTERED) {
impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
@@ -4901,7 +4811,7 @@ lock_rec_convert_impl_to_expl(
record, set one for it */
if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
- index->table->comp, impl_trx)) {
+ impl_trx)) {
lock_rec_add_to_queue(LOCK_REC | LOCK_X
| LOCK_REC_NOT_GAP, rec, index,
@@ -5008,7 +4918,7 @@ lock_sec_rec_modify_check_and_lock(
offsets = rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap);
ut_ad(lock_rec_queue_validate(rec, index, offsets));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c
index 560f51401ac..2f76bf450db 100644
--- a/innobase/log/log0log.c
+++ b/innobase/log/log0log.c
@@ -57,10 +57,11 @@ ulint log_fsp_current_free_limit = 0;
/* Global log system variable */
log_t* log_sys = NULL;
+#ifdef UNIV_DEBUG
ibool log_do_write = TRUE;
ibool log_debug_writes = FALSE;
-
+#endif /* UNIV_DEBUG */
/* These control how often we print warnings if the last checkpoint is too
old */
@@ -974,22 +975,24 @@ log_group_check_flush_completion(
#endif /* UNIV_SYNC_DEBUG */
if (!log_sys->one_flushed && group->n_pending_writes == 0) {
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Log flushed first to group %lu\n", (ulong) group->id);
}
-
+#endif /* UNIV_DEBUG */
log_sys->written_to_some_lsn = log_sys->write_lsn;
log_sys->one_flushed = TRUE;
return(LOG_UNLOCK_NONE_FLUSHED_LOCK);
}
+#ifdef UNIV_DEBUG
if (log_debug_writes && (group->n_pending_writes == 0)) {
fprintf(stderr, "Log flushed to group %lu\n", (ulong) group->id);
}
-
+#endif /* UNIV_DEBUG */
return(0);
}
@@ -1066,12 +1069,13 @@ log_io_complete(
fil_flush(group->space_id);
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Checkpoint info written to group %lu\n",
group->id);
}
-
+#endif /* UNIV_DEBUG */
log_io_complete_checkpoint();
return;
@@ -1133,12 +1137,13 @@ log_group_file_header_flush(
dest_offset = nth_file * group->file_size;
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Writing log file header to group %lu file %lu\n",
(ulong) group->id, (ulong) nth_file);
}
-
+#endif /* UNIV_DEBUG */
if (log_do_write) {
log_sys->n_log_ios++;
@@ -1226,7 +1231,8 @@ loop:
} else {
write_len = len;
}
-
+
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
@@ -1250,7 +1256,7 @@ loop:
+ i * OS_FILE_LOG_BLOCK_SIZE));
}
}
-
+#endif /* UNIV_DEBUG */
/* Calculate the checksums for each log block and write them to
the trailer fields of the log blocks */
@@ -1384,6 +1390,7 @@ loop:
return;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Writing log from %lu %lu up to lsn %lu %lu\n",
@@ -1392,7 +1399,7 @@ loop:
(ulong) ut_dulint_get_high(log_sys->lsn),
(ulong) ut_dulint_get_low(log_sys->lsn));
}
-
+#endif /* UNIV_DEBUG */
log_sys->n_pending_writes++;
group = UT_LIST_GET_FIRST(log_sys->log_groups);
@@ -1961,12 +1968,14 @@ log_checkpoint(
log_sys->next_checkpoint_lsn = oldest_lsn;
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr, "Making checkpoint no %lu at lsn %lu %lu\n",
(ulong) ut_dulint_get_low(log_sys->next_checkpoint_no),
(ulong) ut_dulint_get_high(oldest_lsn),
(ulong) ut_dulint_get_low(oldest_lsn));
}
+#endif /* UNIV_DEBUG */
log_groups_write_checkpoint_info();
@@ -2029,8 +2038,6 @@ log_checkpoint_margin(void)
ulint checkpoint_age;
ulint advance;
dulint oldest_lsn;
- dulint new_oldest;
- ibool do_preflush;
ibool sync;
ibool checkpoint_sync;
ibool do_checkpoint;
@@ -2038,7 +2045,6 @@ log_checkpoint_margin(void)
loop:
sync = FALSE;
checkpoint_sync = FALSE;
- do_preflush = FALSE;
do_checkpoint = FALSE;
mutex_enter(&(log->mutex));
@@ -2058,21 +2064,13 @@ loop:
/* A flush is urgent: we have to do a synchronous preflush */
sync = TRUE;
-
advance = 2 * (age - log->max_modified_age_sync);
-
- new_oldest = ut_dulint_add(oldest_lsn, advance);
-
- do_preflush = TRUE;
-
} else if (age > log->max_modified_age_async) {
/* A flush is not urgent: we do an asynchronous preflush */
advance = age - log->max_modified_age_async;
-
- new_oldest = ut_dulint_add(oldest_lsn, advance);
-
- do_preflush = TRUE;
+ } else {
+ advance = 0;
}
checkpoint_age = ut_dulint_minus(log->lsn, log->last_checkpoint_lsn);
@@ -2096,7 +2094,9 @@ loop:
mutex_exit(&(log->mutex));
- if (do_preflush) {
+ if (advance) {
+ dulint new_oldest = ut_dulint_add(oldest_lsn, advance);
+
success = log_preflush_pool_modified_pages(new_oldest, sync);
/* If the flush succeeded, this thread has done its part
@@ -2347,9 +2347,11 @@ loop:
exit(1);
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr, "Created archive file %s\n", name);
}
+#endif /* UNIV_DEBUG */
ret = os_file_close(file_handle);
@@ -2375,7 +2377,8 @@ loop:
len = group->file_size - (next_offset % group->file_size);
}
-
+
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Archiving starting at lsn %lu %lu, len %lu to group %lu\n",
@@ -2383,6 +2386,7 @@ loop:
(ulong) ut_dulint_get_low(start_lsn),
(ulong) len, (ulong) group->id);
}
+#endif /* UNIV_DEBUG */
log_sys->n_pending_archive_ios++;
@@ -2473,11 +2477,13 @@ log_archive_write_complete_groups(void)
trunc_files = n_files - 1;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes && trunc_files) {
fprintf(stderr,
"Complete file(s) archived to group %lu\n",
(ulong) group->id);
}
+#endif /* UNIV_DEBUG */
/* Calculate the archive file space start lsn */
start_lsn = ut_dulint_subtract(log_sys->next_archived_lsn,
@@ -2500,9 +2506,11 @@ log_archive_write_complete_groups(void)
fil_space_truncate_start(group->archive_space_id,
trunc_files * group->file_size);
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fputs("Archiving writes completed\n", stderr);
}
+#endif /* UNIV_DEBUG */
}
/**********************************************************
@@ -2519,9 +2527,11 @@ log_archive_check_completion_low(void)
if (log_sys->n_pending_archive_ios == 0
&& log_sys->archiving_phase == LOG_ARCHIVE_READ) {
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fputs("Archiving read completed\n", stderr);
}
+#endif /* UNIV_DEBUG */
/* Archive buffer has now been read in: start archive writes */
@@ -2665,6 +2675,7 @@ loop:
log_sys->next_archived_lsn = limit_lsn;
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Archiving from lsn %lu %lu to lsn %lu %lu\n",
@@ -2673,6 +2684,7 @@ loop:
(ulong) ut_dulint_get_high(limit_lsn),
(ulong) ut_dulint_get_low(limit_lsn));
}
+#endif /* UNIV_DEBUG */
/* Read the log segment to the archive buffer */
@@ -2775,12 +2787,14 @@ log_archive_close_groups(
group->archived_file_no += 2;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"Incrementing arch file no to %lu in log group %lu\n",
(ulong) group->archived_file_no + 2,
(ulong) group->id);
}
+#endif /* UNIV_DEBUG */
}
}
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 6597122f104..42e854398ba 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -477,6 +477,7 @@ recv_find_max_checkpoint(
max_no = ut_dulint_zero;
*max_group = NULL;
+ *max_field = 0;
buf = log_sys->checkpoint_buf;
@@ -489,6 +490,7 @@ recv_find_max_checkpoint(
log_group_read_checkpoint_info(group, field);
if (!recv_check_cp_is_consistent(buf)) {
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Checkpoint in group %lu at %lu invalid, %lu\n",
@@ -498,7 +500,7 @@ recv_find_max_checkpoint(
+ LOG_CHECKPOINT_CHECKSUM_1));
}
-
+#endif /* UNIV_DEBUG */
goto not_consistent;
}
@@ -511,13 +513,15 @@ recv_find_max_checkpoint(
checkpoint_no =
mach_read_from_8(buf + LOG_CHECKPOINT_NO);
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Checkpoint number %lu found in group %lu\n",
(ulong) ut_dulint_get_low(checkpoint_no),
(ulong) group->id);
}
-
+#endif /* UNIV_DEBUG */
+
if (ut_dulint_cmp(checkpoint_no, max_no) >= 0) {
*max_group = group;
*max_field = field;
@@ -540,7 +544,6 @@ recv_find_max_checkpoint(
"InnoDB: to create the InnoDB data files, but log file creation failed.\n"
"InnoDB: If that is the case, please refer to\n"
"InnoDB: http://dev.mysql.com/doc/mysql/en/Error_creating_InnoDB.html\n");
-
return(DB_ERROR);
}
@@ -765,6 +768,8 @@ recv_parse_or_apply_log_rec_body(
case MLOG_REC_INSERT: case MLOG_COMP_REC_INSERT:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_REC_INSERT, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr,
index, page, mtr);
}
@@ -772,20 +777,29 @@ recv_parse_or_apply_log_rec_body(
case MLOG_REC_CLUST_DELETE_MARK: case MLOG_COMP_REC_CLUST_DELETE_MARK:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_REC_CLUST_DELETE_MARK, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = btr_cur_parse_del_mark_set_clust_rec(ptr,
end_ptr, index, page);
}
break;
- case MLOG_REC_SEC_DELETE_MARK: case MLOG_COMP_REC_SEC_DELETE_MARK:
- if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
- type == MLOG_COMP_REC_SEC_DELETE_MARK, &index))) {
- ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr,
- index, page);
+ case MLOG_COMP_REC_SEC_DELETE_MARK:
+ /* This log record type is obsolete, but we process it for
+ backward compatibility with MySQL 5.0.3 and 5.0.4. */
+ ut_a(!page || page_is_comp(page));
+ ptr = mlog_parse_index(ptr, end_ptr, TRUE, &index);
+ if (!ptr) {
+ break;
}
+ /* Fall through */
+ case MLOG_REC_SEC_DELETE_MARK:
+ ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr, page);
break;
case MLOG_REC_UPDATE_IN_PLACE: case MLOG_COMP_REC_UPDATE_IN_PLACE:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_REC_UPDATE_IN_PLACE, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = btr_cur_parse_update_in_place(ptr, end_ptr,
page, index);
}
@@ -795,6 +809,8 @@ recv_parse_or_apply_log_rec_body(
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_LIST_END_DELETE
|| type == MLOG_COMP_LIST_START_DELETE, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = page_parse_delete_rec_list(type, ptr, end_ptr,
index, page, mtr);
}
@@ -802,6 +818,8 @@ recv_parse_or_apply_log_rec_body(
case MLOG_LIST_END_COPY_CREATED: case MLOG_COMP_LIST_END_COPY_CREATED:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_LIST_END_COPY_CREATED, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = page_parse_copy_rec_list_to_created_page(ptr,
end_ptr, index, page, mtr);
}
@@ -809,6 +827,8 @@ recv_parse_or_apply_log_rec_body(
case MLOG_PAGE_REORGANIZE: case MLOG_COMP_PAGE_REORGANIZE:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_PAGE_REORGANIZE, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = btr_parse_page_reorganize(ptr, end_ptr, index,
page, mtr);
}
@@ -841,6 +861,8 @@ recv_parse_or_apply_log_rec_body(
case MLOG_REC_DELETE: case MLOG_COMP_REC_DELETE:
if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
type == MLOG_COMP_REC_DELETE, &index))) {
+ ut_a(!page
+ || (ibool)!!page_is_comp(page)==index->table->comp);
ptr = page_cur_parse_delete_rec(ptr, end_ptr,
index, page, mtr);
}
@@ -1153,6 +1175,7 @@ recv_recover_page(
}
modification_to_page = FALSE;
+ start_lsn = end_lsn = ut_dulint_zero;
recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
@@ -1186,6 +1209,7 @@ recv_recover_page(
start_lsn = recv->start_lsn;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Applying log rec type %lu len %lu to space %lu page no %lu\n",
@@ -1193,6 +1217,7 @@ recv_recover_page(
(ulong) recv_addr->space,
(ulong) recv_addr->page_no);
}
+#endif /* UNIV_DEBUG */
recv_parse_or_apply_log_rec_body(recv->type, buf,
buf + recv->len, page, &mtr);
@@ -1779,6 +1804,8 @@ recv_parse_log_rec(
{
byte* new_ptr;
+ *body = NULL;
+
if (ptr == end_ptr) {
return(0);
@@ -1801,25 +1828,25 @@ recv_parse_log_rec(
new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
page_no);
- if (!new_ptr) {
+ *body = new_ptr;
+
+ if (UNIV_UNLIKELY(!new_ptr)) {
return(0);
}
/* Check that page_no is sensible */
- if (*page_no > 0x8FFFFFFFUL) {
+ if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) {
recv_sys->found_corrupt_log = TRUE;
return(0);
}
- *body = new_ptr;
-
new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr,
NULL, NULL);
- if (new_ptr == NULL) {
+ if (UNIV_UNLIKELY(new_ptr == NULL)) {
return(0);
}
@@ -2013,12 +2040,14 @@ loop:
recv_sys->recovered_offset += len;
recv_sys->recovered_lsn = new_recovered_lsn;
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Parsed a single log rec type %lu len %lu space %lu page no %lu\n",
(ulong) type, (ulong) len, (ulong) space,
(ulong) page_no);
}
+#endif /* UNIV_DEBUG */
if (type == MLOG_DUMMY_RECORD) {
/* Do nothing */
@@ -2101,13 +2130,15 @@ loop:
body, ptr + len);
#endif /* UNIV_LOG_REPLICATE */
}
-
+
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Parsed a multi log rec type %lu len %lu space %lu page no %lu\n",
(ulong) type, (ulong) len, (ulong) space,
(ulong) page_no);
}
+#endif /* UNIV_DEBUG */
total_len += len;
n_recs++;
@@ -2514,6 +2545,7 @@ recv_group_scan_log_recs(
start_lsn = end_lsn;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Scanned group %lu up to log sequence number %lu %lu\n",
@@ -2521,6 +2553,7 @@ recv_group_scan_log_recs(
(ulong) ut_dulint_get_high(*group_scanned_lsn),
(ulong) ut_dulint_get_low(*group_scanned_lsn));
}
+#endif /* UNIV_DEBUG */
}
/************************************************************
@@ -2906,10 +2939,12 @@ recv_recovery_from_checkpoint_finish(void)
recv_apply_hashed_log_recs(TRUE);
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Log records applied to the database\n");
}
+#endif /* UNIV_DEBUG */
if (recv_needed_recovery) {
trx_sys_print_mysql_master_log_pos();
@@ -3246,6 +3281,7 @@ ask_again:
break;
}
+#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr,
"InnoDB: Archive read starting at lsn %lu %lu, len %lu from file %s\n",
@@ -3253,6 +3289,7 @@ ask_again:
(ulong) ut_dulint_get_low(start_lsn),
(ulong) len, name);
}
+#endif /* UNIV_DEBUG */
fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE,
group->archive_space_id, read_offset / UNIV_PAGE_SIZE,
diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c
index 4f826f242e8..0308619073a 100644
--- a/innobase/mtr/mtr0log.c
+++ b/innobase/mtr/mtr0log.c
@@ -15,6 +15,7 @@ Created 12/7/1995 Heikki Tuuri
#include "buf0buf.h"
#include "dict0boot.h"
#include "log0recv.h"
+#include "page0page.h"
/************************************************************
Catenates n bytes to the mtr log. */
@@ -22,9 +23,9 @@ Catenates n bytes to the mtr log. */
void
mlog_catenate_string(
/*=================*/
- mtr_t* mtr, /* in: mtr */
- byte* str, /* in: string to write */
- ulint len) /* in: string length */
+ mtr_t* mtr, /* in: mtr */
+ const byte* str, /* in: string to write */
+ ulint len) /* in: string length */
{
dyn_array_t* mlog;
@@ -301,14 +302,15 @@ corresponding log record to the mini-transaction log. */
void
mlog_write_string(
/*==============*/
- byte* ptr, /* in: pointer where to write */
- byte* str, /* in: string to write */
- ulint len, /* in: string length */
- mtr_t* mtr) /* in: mini-transaction handle */
+ byte* ptr, /* in: pointer where to write */
+ const byte* str, /* in: string to write */
+ ulint len, /* in: string length */
+ mtr_t* mtr) /* in: mini-transaction handle */
{
byte* log_ptr;
- if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
+ if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero)
+ || UNIV_UNLIKELY(ptr >= buf_pool->high_end)) {
fprintf(stderr,
"InnoDB: Error: trying to write to a stray memory location %p\n", ptr);
ut_error;
@@ -405,7 +407,9 @@ mlog_open_and_write_index(
const byte* log_start;
const byte* log_end;
- if (!index->table->comp) {
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
+
+ if (!page_rec_is_comp(rec)) {
log_start = log_ptr = mlog_open(mtr, 11 + size);
if (!log_ptr) {
return(NULL); /* logging is disabled */
@@ -498,6 +502,8 @@ mlog_parse_index(
dict_table_t* table;
dict_index_t* ind;
+ ut_ad(comp == FALSE || comp == TRUE);
+
if (comp) {
if (end_ptr < ptr + 4) {
return(NULL);
diff --git a/innobase/mtr/mtr0mtr.c b/innobase/mtr/mtr0mtr.c
index 6e918806eb1..da045be1f62 100644
--- a/innobase/mtr/mtr0mtr.c
+++ b/innobase/mtr/mtr0mtr.c
@@ -48,16 +48,11 @@ mtr_memo_slot_release(
object = slot->object;
type = slot->type;
- if (object != NULL) {
+ if (UNIV_LIKELY(object != NULL)) {
if (type <= MTR_MEMO_BUF_FIX) {
buf_page_release((buf_block_t*)object, type, mtr);
} else if (type == MTR_MEMO_S_LOCK) {
rw_lock_s_unlock((rw_lock_t*)object);
-#ifndef UNIV_DEBUG
- } else {
- rw_lock_x_unlock((rw_lock_t*)object);
- }
-#endif
#ifdef UNIV_DEBUG
} else if (type == MTR_MEMO_X_LOCK) {
rw_lock_x_unlock((rw_lock_t*)object);
@@ -65,8 +60,11 @@ mtr_memo_slot_release(
ut_ad(type == MTR_MEMO_MODIFY);
ut_ad(mtr_memo_contains(mtr, object,
MTR_MEMO_PAGE_X_FIX));
- }
+#else
+ } else {
+ rw_lock_x_unlock((rw_lock_t*)object);
#endif
+ }
}
slot->object = NULL;
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index ac5d1c72c72..48dc808e36c 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -83,7 +83,7 @@ struct os_aio_slot_struct{
made and only the slot message
needs to be passed to the caller
of os_aio_simulated_handle */
- void* message1; /* message which is given by the */
+ fil_node_t* message1; /* message which is given by the */
void* message2; /* the requester of an aio operation
and which can be used to identify
which pending aio operation was
@@ -133,17 +133,17 @@ os_event_t* os_aio_segment_wait_events = NULL;
/* The aio arrays for non-ibuf i/o and ibuf i/o, as well as sync aio. These
are NULL when the module has not yet been initialized. */
-os_aio_array_t* os_aio_read_array = NULL;
-os_aio_array_t* os_aio_write_array = NULL;
-os_aio_array_t* os_aio_ibuf_array = NULL;
-os_aio_array_t* os_aio_log_array = NULL;
-os_aio_array_t* os_aio_sync_array = NULL;
+static os_aio_array_t* os_aio_read_array = NULL;
+static os_aio_array_t* os_aio_write_array = NULL;
+static os_aio_array_t* os_aio_ibuf_array = NULL;
+static os_aio_array_t* os_aio_log_array = NULL;
+static os_aio_array_t* os_aio_sync_array = NULL;
-ulint os_aio_n_segments = ULINT_UNDEFINED;
+static ulint os_aio_n_segments = ULINT_UNDEFINED;
/* If the following is TRUE, read i/o handler threads try to
wait until a batch of new read requests have been posted */
-ibool os_aio_recommend_sleep_for_read_threads = FALSE;
+static ibool os_aio_recommend_sleep_for_read_threads = FALSE;
ulint os_n_file_reads = 0;
ulint os_bytes_read_since_printout = 0;
@@ -158,7 +158,7 @@ ibool os_has_said_disk_full = FALSE;
/* The mutex protecting the following counts of pending pread and pwrite
operations */
-os_mutex_t os_file_count_mutex;
+static os_mutex_t os_file_count_mutex;
ulint os_file_n_pending_preads = 0;
ulint os_file_n_pending_pwrites = 0;
@@ -1653,7 +1653,7 @@ os_file_get_size_as_iblonglong(
}
/***************************************************************************
-Sets a file size. This function can be used to extend or truncate a file. */
+Write the specified number of zeros to a newly created file. */
ibool
os_file_set_size(
@@ -1666,47 +1666,46 @@ os_file_set_size(
size */
ulint size_high)/* in: most significant 32 bits of size */
{
- ib_longlong offset;
- ib_longlong low;
- ulint n_bytes;
+ ib_longlong current_size;
+ ib_longlong desired_size;
ibool ret;
byte* buf;
byte* buf2;
- ulint i;
+ ulint buf_size;
ut_a(size == (size & 0xFFFFFFFF));
- /* We use a very big 8 MB buffer in writing because Linux may be
- extremely slow in fsync on 1 MB writes */
+ current_size = 0;
+ desired_size = (ib_longlong)size + (((ib_longlong)size_high) << 32);
- buf2 = ut_malloc(UNIV_PAGE_SIZE * 513);
+ /* Write up to 1 megabyte at a time. */
+ buf_size = ut_min(64, (ulint) (desired_size / UNIV_PAGE_SIZE))
+ * UNIV_PAGE_SIZE;
+ buf2 = ut_malloc(buf_size + UNIV_PAGE_SIZE);
/* Align the buffer for possible raw i/o */
buf = ut_align(buf2, UNIV_PAGE_SIZE);
/* Write buffer full of zeros */
- for (i = 0; i < UNIV_PAGE_SIZE * 512; i++) {
- buf[i] = '\0';
- }
-
- offset = 0;
- low = (ib_longlong)size + (((ib_longlong)size_high) << 32);
+ memset(buf, 0, buf_size);
- if (low >= (ib_longlong)(100 * 1024 * 1024)) {
+ if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, "InnoDB: Progress in MB:");
}
- while (offset < low) {
- if (low - offset < UNIV_PAGE_SIZE * 512) {
- n_bytes = (ulint)(low - offset);
- } else {
- n_bytes = UNIV_PAGE_SIZE * 512;
- }
-
+ while (current_size < desired_size) {
+ ulint n_bytes;
+
+ if (desired_size - current_size < (ib_longlong) buf_size) {
+ n_bytes = (ulint) (desired_size - current_size);
+ } else {
+ n_bytes = buf_size;
+ }
+
ret = os_file_write(name, file, buf,
- (ulint)(offset & 0xFFFFFFFF),
- (ulint)(offset >> 32),
+ (ulint)(current_size & 0xFFFFFFFF),
+ (ulint)(current_size >> 32),
n_bytes);
if (!ret) {
ut_free(buf2);
@@ -1714,18 +1713,18 @@ os_file_set_size(
}
/* Print about progress for each 100 MB written */
- if ((ib_longlong) (offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024)
- != offset / (ib_longlong)(100 * 1024 * 1024)) {
+ if ((current_size + n_bytes) / (ib_longlong)(100 * 1024 * 1024)
+ != current_size / (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, " %lu00",
- (ulong) ((offset + n_bytes)
+ (ulong) ((current_size + n_bytes)
/ (ib_longlong)(100 * 1024 * 1024)));
}
- offset += n_bytes;
+ current_size += n_bytes;
}
- if (low >= (ib_longlong)(100 * 1024 * 1024)) {
+ if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, "\n");
}
@@ -3025,7 +3024,7 @@ os_aio_array_reserve_slot(
/* out: pointer to slot */
ulint type, /* in: OS_FILE_READ or OS_FILE_WRITE */
os_aio_array_t* array, /* in: aio array */
- void* message1,/* in: message to be passed along with
+ fil_node_t* message1,/* in: message to be passed along with
the aio operation */
void* message2,/* in: message to be passed along with
the aio operation */
@@ -3287,7 +3286,7 @@ os_aio(
ulint offset_high, /* in: most significant 32 bits of
offset */
ulint n, /* in: number of bytes to read or write */
- void* message1,/* in: messages for the aio handler (these
+ fil_node_t* message1,/* in: messages for the aio handler (these
can be used to identify a completed aio
operation); if mode is OS_AIO_SYNC, these
are ignored */
@@ -3299,7 +3298,7 @@ os_aio(
ibool retval;
BOOL ret = TRUE;
DWORD len = (DWORD) n;
- void* dummy_mess1;
+ struct fil_node_struct * dummy_mess1;
void* dummy_mess2;
ulint dummy_type;
#endif
@@ -3472,7 +3471,7 @@ os_aio_windows_handle(
ignored */
ulint pos, /* this parameter is used only in sync aio:
wait for the aio slot at this position */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -3563,7 +3562,7 @@ os_aio_posix_handle(
/*================*/
/* out: TRUE if the aio operation succeeded */
ulint array_no, /* in: array number 0 - 3 */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -3644,7 +3643,7 @@ os_aio_simulated_handle(
i/o thread, segment 1 the log i/o thread,
then follow the non-ibuf read threads, and as
the last are the non-ibuf write threads */
- void** message1, /* out: the messages passed with the aio
+ fil_node_t**message1, /* out: the messages passed with the aio
request; note that also in the case where
the aio operation failed, these output
parameters are valid and can be used to
@@ -4182,6 +4181,7 @@ os_aio_refresh_stats(void)
os_last_printout = time(NULL);
}
+#ifdef UNIV_DEBUG
/**************************************************************************
Checks that all slots in the system have been freed, that is, there are
no pending io operations. */
@@ -4241,3 +4241,4 @@ os_aio_all_slots_free(void)
return(FALSE);
}
+#endif /* UNIV_DEBUG */
diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c
index 7738f5a34f0..d0b89e81787 100644
--- a/innobase/page/page0cur.c
+++ b/innobase/page/page0cur.c
@@ -47,7 +47,6 @@ page_cur_try_search_shortcut(
not yet completely matched */
page_cur_t* cursor) /* out: page cursor */
{
- int cmp;
rec_t* rec;
rec_t* next_rec;
ulint low_match;
@@ -79,9 +78,8 @@ page_cur_try_search_shortcut(
up_match = low_match;
up_bytes = low_bytes;
- cmp = page_cmp_dtuple_rec_with_match(tuple, rec, offsets, &low_match,
- &low_bytes);
- if (cmp == -1) {
+ if (page_cmp_dtuple_rec_with_match(tuple, rec, offsets,
+ &low_match, &low_bytes) < 0) {
goto exit_func;
}
@@ -89,9 +87,8 @@ page_cur_try_search_shortcut(
offsets = rec_get_offsets(next_rec, index, offsets,
dtuple_get_n_fields(tuple), &heap);
- cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets,
- &up_match, &up_bytes);
- if (cmp != -1) {
+ if (page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets,
+ &up_match, &up_bytes) >= 0) {
goto exit_func;
}
@@ -115,7 +112,7 @@ page_cur_try_search_shortcut(
ut_a(*ilow_matched_fields == low_match);
ut_a(*ilow_matched_bytes == low_bytes);
#endif
- if (next_rec != page_get_supremum_rec(page)) {
+ if (!page_rec_is_supremum(next_rec)) {
*iup_matched_fields = up_match;
*iup_matched_bytes = up_bytes;
@@ -129,7 +126,7 @@ page_cur_try_search_shortcut(
#endif
success = TRUE;
exit_func:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(success);
@@ -137,6 +134,7 @@ exit_func:
#endif
+#ifdef PAGE_CUR_LE_OR_EXTENDS
/********************************************************************
Checks if the nth field in a record is a character type field which extends
the nth field in tuple, i.e., the field is longer or equal in length and has
@@ -185,6 +183,7 @@ page_cur_rec_field_extends(
return(FALSE);
}
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
/********************************************************************
Searches the right position for a page cursor. */
@@ -239,10 +238,17 @@ page_cur_search_with_match(
&& ilow_matched_fields && ilow_matched_bytes && cursor);
ut_ad(dtuple_validate(tuple));
ut_ad(dtuple_check_typed(tuple));
+#ifdef UNIV_DEBUG
+# ifdef PAGE_CUR_DBG
+ if (mode != PAGE_CUR_DBG)
+# endif /* PAGE_CUR_DBG */
+# ifdef PAGE_CUR_LE_OR_EXTENDS
+ if (mode != PAGE_CUR_LE_OR_EXTENDS)
+# endif /* PAGE_CUR_LE_OR_EXTENDS */
ut_ad((mode == PAGE_CUR_L) || (mode == PAGE_CUR_LE)
- || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)
- || (mode == PAGE_CUR_LE_OR_EXTENDS) || (mode == PAGE_CUR_DBG));
-
+ || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE));
+#endif /* UNIV_DEBUG */
+
page_check_dir(page);
#ifdef PAGE_CUR_ADAPT
@@ -261,16 +267,18 @@ page_cur_search_with_match(
return;
}
}
-/*#ifdef UNIV_SEARCH_DEBUG */
+# ifdef PAGE_CUR_DBG
if (mode == PAGE_CUR_DBG) {
mode = PAGE_CUR_LE;
}
-/*#endif */
+# endif
#endif
/* The following flag does not work for non-latin1 char sets because
cmp_full_field does not tell how many bytes matched */
+#ifdef PAGE_CUR_LE_OR_EXTENDS
ut_a(mode != PAGE_CUR_LE_OR_EXTENDS);
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
/* If mode PAGE_CUR_G is specified, we are trying to position the
cursor to answer a query of the form "tuple < X", where tuple is
@@ -308,33 +316,36 @@ page_cur_search_with_match(
cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
&cur_matched_fields,
&cur_matched_bytes);
- if (cmp == 1) {
+ if (UNIV_LIKELY(cmp > 0)) {
+low_slot_match:
low = mid;
low_matched_fields = cur_matched_fields;
low_matched_bytes = cur_matched_bytes;
- } else if (cmp == -1) {
+ } else if (UNIV_LIKELY(cmp /* == -1 */)) {
+#ifdef PAGE_CUR_LE_OR_EXTENDS
if (mode == PAGE_CUR_LE_OR_EXTENDS
&& page_cur_rec_field_extends(tuple, mid_rec,
offsets, cur_matched_fields)) {
- low = mid;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
- } else {
- up = mid;
- up_matched_fields = cur_matched_fields;
- up_matched_bytes = cur_matched_bytes;
- }
- } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
- || mode == PAGE_CUR_LE_OR_EXTENDS) {
- low = mid;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
- } else {
+ goto low_slot_match;
+ }
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+up_slot_match:
up = mid;
up_matched_fields = cur_matched_fields;
up_matched_bytes = cur_matched_bytes;
+
+ } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
+#ifdef PAGE_CUR_LE_OR_EXTENDS
+ || mode == PAGE_CUR_LE_OR_EXTENDS
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+ ) {
+
+ goto low_slot_match;
+ } else {
+
+ goto up_slot_match;
}
}
@@ -360,32 +371,35 @@ page_cur_search_with_match(
cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
&cur_matched_fields,
&cur_matched_bytes);
- if (cmp == 1) {
+ if (UNIV_LIKELY(cmp > 0)) {
+low_rec_match:
low_rec = mid_rec;
low_matched_fields = cur_matched_fields;
low_matched_bytes = cur_matched_bytes;
- } else if (cmp == -1) {
+ } else if (UNIV_LIKELY(cmp /* == -1 */)) {
+#ifdef PAGE_CUR_LE_OR_EXTENDS
if (mode == PAGE_CUR_LE_OR_EXTENDS
&& page_cur_rec_field_extends(tuple, mid_rec,
offsets, cur_matched_fields)) {
- low_rec = mid_rec;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
- } else {
- up_rec = mid_rec;
- up_matched_fields = cur_matched_fields;
- up_matched_bytes = cur_matched_bytes;
+
+ goto low_rec_match;
}
- } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
- || mode == PAGE_CUR_LE_OR_EXTENDS) {
- low_rec = mid_rec;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
- } else {
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+up_rec_match:
up_rec = mid_rec;
up_matched_fields = cur_matched_fields;
up_matched_bytes = cur_matched_bytes;
+ } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
+#ifdef PAGE_CUR_LE_OR_EXTENDS
+ || mode == PAGE_CUR_LE_OR_EXTENDS
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+ ) {
+
+ goto low_rec_match;
+ } else {
+
+ goto up_rec_match;
}
}
@@ -451,7 +465,7 @@ page_cur_search_with_match(
*iup_matched_bytes = up_matched_bytes;
*ilow_matched_fields = low_matched_fields;
*ilow_matched_bytes = low_matched_bytes;
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -515,8 +529,12 @@ page_cur_insert_rec_write_log(
byte* log_ptr;
byte* log_end;
ulint i;
+ ulint comp;
ut_a(rec_size < UNIV_PAGE_SIZE);
+ ut_ad(buf_frame_align(insert_rec) == buf_frame_align(cursor_rec));
+ ut_ad(!page_rec_is_comp(insert_rec) == !index->table->comp);
+ comp = page_rec_is_comp(insert_rec);
{
mem_heap_t* heap = NULL;
@@ -539,7 +557,7 @@ page_cur_insert_rec_write_log(
ut_ad(rec_size == rec_offs_size(ins_offs));
cur_rec_size = rec_offs_size(cur_offs);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -565,7 +583,7 @@ page_cur_insert_rec_write_log(
ins_ptr++;
cur_ptr++;
} else if ((i < extra_size)
- && (i >= extra_size - (index->table->comp
+ && (i >= extra_size - (comp
? REC_N_NEW_EXTRA_BYTES
: REC_N_OLD_EXTRA_BYTES))) {
i = extra_size;
@@ -580,7 +598,7 @@ page_cur_insert_rec_write_log(
if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
log_ptr = mlog_open_and_write_index(mtr, insert_rec, index,
- index->table->comp
+ comp
? MLOG_COMP_REC_INSERT : MLOG_REC_INSERT,
2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
@@ -605,8 +623,8 @@ page_cur_insert_rec_write_log(
log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
}
- if ((rec_get_info_and_status_bits(insert_rec, index->table->comp) !=
- rec_get_info_and_status_bits(cursor_rec, index->table->comp))
+ if ((rec_get_info_and_status_bits(insert_rec, comp) !=
+ rec_get_info_and_status_bits(cursor_rec, comp))
|| (extra_size != cur_extra_size)
|| (rec_size != cur_rec_size)) {
@@ -622,8 +640,7 @@ page_cur_insert_rec_write_log(
if (extra_info_yes) {
/* Write the info bits */
mach_write_to_1(log_ptr,
- rec_get_info_and_status_bits(insert_rec,
- index->table->comp));
+ rec_get_info_and_status_bits(insert_rec, comp));
log_ptr++;
/* Write the record origin offset */
@@ -757,6 +774,8 @@ page_cur_parse_insert_rec(
return(ptr + end_seg_len);
}
+ ut_ad(!!page_is_comp(page) == index->table->comp);
+
/* Read from the log the inserted index record end segment which
differs from the cursor record */
@@ -771,7 +790,7 @@ page_cur_parse_insert_rec(
if (extra_info_yes == 0) {
info_and_status_bits = rec_get_info_and_status_bits(
- cursor_rec, index->table->comp);
+ cursor_rec, page_is_comp(page));
origin_offset = rec_offs_extra_size(offsets);
mismatch_index = rec_offs_size(offsets) - end_seg_len;
}
@@ -807,7 +826,7 @@ page_cur_parse_insert_rec(
ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
- rec_set_info_and_status_bits(buf + origin_offset, index->table->comp,
+ rec_set_info_and_status_bits(buf + origin_offset, page_is_comp(page),
info_and_status_bits);
page_cur_position(cursor_rec, &cursor);
@@ -821,7 +840,7 @@ page_cur_parse_insert_rec(
mem_free(buf);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -861,7 +880,7 @@ page_cur_insert_rec_low(
rec_t* owner_rec;
ulint n_owned;
mem_heap_t* heap = NULL;
- ibool comp = index->table->comp;
+ ulint comp;
ut_ad(cursor && mtr);
ut_ad(tuple || rec);
@@ -869,8 +888,8 @@ page_cur_insert_rec_low(
ut_ad(rec || dtuple_check_typed(tuple));
page = page_cur_get_page(cursor);
-
- ut_ad(page_is_comp(page) == comp);
+ comp = page_is_comp(page);
+ ut_ad(index->table->comp == !!comp);
ut_ad(cursor->rec != page_get_supremum_rec(page));
@@ -890,7 +909,7 @@ page_cur_insert_rec_low(
insert_buf = page_mem_alloc(page, rec_size, index, &heap_no);
if (insert_buf == NULL) {
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(NULL);
@@ -980,7 +999,7 @@ page_cur_insert_rec_low(
page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec,
index, mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(insert_rec);
@@ -1000,8 +1019,10 @@ page_copy_rec_list_to_created_page_write_log(
{
byte* log_ptr;
+ ut_ad(!!page_is_comp(page) == index->table->comp);
+
log_ptr = mlog_open_and_write_index(mtr, page, index,
- index->table->comp
+ page_is_comp(page)
? MLOG_COMP_LIST_END_COPY_CREATED
: MLOG_LIST_END_COPY_CREATED, 4);
ut_a(log_ptr);
@@ -1084,7 +1105,7 @@ page_copy_rec_list_end_to_created_page(
ulint log_mode;
byte* log_ptr;
ulint log_data_len;
- ibool comp = page_is_comp(page);
+ ulint comp = page_is_comp(page);
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -1186,7 +1207,7 @@ page_copy_rec_list_end_to_created_page(
slot_index--;
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -1230,8 +1251,10 @@ page_cur_delete_rec_write_log(
{
byte* log_ptr;
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
+
log_ptr = mlog_open_and_write_index(mtr, rec, index,
- index->table->comp
+ page_rec_is_comp(rec)
? MLOG_COMP_REC_DELETE
: MLOG_REC_DELETE, 2);
@@ -1242,7 +1265,7 @@ page_cur_delete_rec_write_log(
}
/* Write the cursor rec offset as a 2-byte ulint */
- mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
+ mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
mlog_close(mtr, log_ptr + 2);
}
@@ -1285,7 +1308,7 @@ page_cur_parse_delete_rec(
page_cur_delete_rec(&cursor, index,
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap), mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -1320,6 +1343,7 @@ page_cur_delete_rec(
page = page_cur_get_page(cursor);
current_rec = cursor->rec;
ut_ad(rec_offs_validate(current_rec, index, offsets));
+ ut_ad(!!page_is_comp(page) == index->table->comp);
/* The record must not be the supremum or infimum record. */
ut_ad(current_rec != page_get_supremum_rec(page));
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index f3217e91f58..7e09cdf073e 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -72,65 +72,70 @@ page_dir_find_owner_slot(
/* out: the directory slot number */
rec_t* rec) /* in: the physical record */
{
- ulint i;
- ulint steps = 0;
- page_t* page;
- page_dir_slot_t* slot;
- rec_t* original_rec = rec;
- ibool comp;
-
+ page_t* page;
+ register uint16 rec_offs_bytes;
+ register page_dir_slot_t* slot;
+ register const page_dir_slot_t* first_slot;
+ register rec_t* r = rec;
+
ut_ad(page_rec_check(rec));
page = buf_frame_align(rec);
- comp = page_is_comp(page);
-
- while (rec_get_n_owned(rec, comp) == 0) {
- steps++;
- rec = page_rec_get_next(rec);
+ first_slot = page_dir_get_nth_slot(page, 0);
+ slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
+
+ if (page_is_comp(page)) {
+ while (rec_get_n_owned(r, TRUE) == 0) {
+ r = page + rec_get_next_offs(r, TRUE);
+ ut_ad(r >= page + PAGE_NEW_SUPREMUM);
+ ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
+ }
+ } else {
+ while (rec_get_n_owned(r, FALSE) == 0) {
+ r = page + rec_get_next_offs(r, FALSE);
+ ut_ad(r >= page + PAGE_OLD_SUPREMUM);
+ ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
+ }
}
-
- page = buf_frame_align(rec);
- i = page_dir_get_n_slots(page) - 1;
- slot = page_dir_get_nth_slot(page, i);
+ rec_offs_bytes = mach_encode_2(r - page);
- while (page_dir_slot_get_rec(slot) != rec) {
+ while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
- if (i == 0) {
+ if (UNIV_UNLIKELY(slot == first_slot)) {
fprintf(stderr,
"InnoDB: Probable data corruption on page %lu\n"
"InnoDB: Original record ",
(ulong) buf_frame_get_page_no(page));
- if (comp) {
+ if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
- rec_print_old(stderr, original_rec);
+ rec_print_old(stderr, rec);
}
- fprintf(stderr, "\n"
- "InnoDB: on that page. Steps %lu.\n", (ulong) steps);
- fputs(
+ fputs("\n"
+ "InnoDB: on that page.\n"
"InnoDB: Cannot find the dir slot for record ",
stderr);
- if (comp) {
+ if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
- rec_print_old(stderr, rec);
+ rec_print_old(stderr, page
+ + mach_decode_2(rec_offs_bytes));
}
fputs("\n"
"InnoDB: on that page!\n", stderr);
buf_page_print(page);
- ut_error;
- }
+ ut_error;
+ }
- i--;
- slot = page_dir_get_nth_slot(page, i);
+ slot += PAGE_DIR_SLOT_SIZE;
}
- return(i);
+ return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE);
}
/******************************************************************
@@ -252,13 +257,13 @@ page_mem_alloc(
*heap_no = rec_get_heap_no(rec, page_is_comp(page));
block = rec_get_start(rec, offsets);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(block);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -290,7 +295,7 @@ page_create_write_log(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
mlog_write_initial_log_record(frame,
comp ? MLOG_COMP_PAGE_CREATE : MLOG_PAGE_CREATE, mtr);
@@ -305,7 +310,7 @@ page_parse_create(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr __attribute__((unused)), /* in: buffer end */
- ibool comp, /* in: TRUE=compact page format */
+ ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -330,7 +335,7 @@ page_create(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
- ibool comp) /* in: TRUE=compact page format */
+ ulint comp) /* in: nonzero=compact page format */
{
page_dir_slot_t* slot;
mem_heap_t* heap;
@@ -396,9 +401,9 @@ page_create(
dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
field = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(field, "supremum", 9 - comp);
+ dfield_set_data(field, "supremum", comp ? 8 : 9);
dtype_set(dfield_get_type(field),
- DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 9 - comp, 0);
+ DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9, 0);
supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
@@ -478,10 +483,11 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur1);
}
- ut_a(index->table->comp == page_is_comp(page));
- ut_a(index->table->comp == page_is_comp(new_page));
+ ut_a((ibool)!!page_is_comp(new_page) == index->table->comp);
+ ut_a(page_is_comp(new_page) == page_is_comp(page));
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
- (index->table->comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
+ (page_is_comp(new_page)
+ ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
page_cur_set_before_first(new_page, &cur2);
@@ -489,12 +495,15 @@ page_copy_rec_list_end_no_locks(
sup = page_get_supremum_rec(page);
- while (sup != page_cur_get_rec(&cur1)) {
+ for (;;) {
rec_t* cur1_rec = page_cur_get_rec(&cur1);
+ if (cur1_rec == sup) {
+ break;
+ }
offsets = rec_get_offsets(cur1_rec, index, offsets,
ULINT_UNDEFINED, &heap);
- if (!page_cur_rec_insert(&cur2, cur1_rec, index,
- offsets, mtr)) {
+ if (UNIV_UNLIKELY(!page_cur_rec_insert(&cur2, cur1_rec, index,
+ offsets, mtr))) {
/* Track an assertion failure reported on the mailing
list on June 18th, 2003 */
@@ -514,7 +523,7 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur2);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -608,7 +617,7 @@ page_copy_rec_list_start(
btr_search_move_or_delete_hash_entries(new_page, page, index);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -619,7 +628,6 @@ UNIV_INLINE
void
page_delete_rec_list_write_log(
/*===========================*/
- page_t* page, /* in: index page */
rec_t* rec, /* in: record on page */
dict_index_t* index, /* in: record descriptor */
byte type, /* in: operation type:
@@ -632,10 +640,10 @@ page_delete_rec_list_write_log(
|| type == MLOG_COMP_LIST_END_DELETE
|| type == MLOG_COMP_LIST_START_DELETE);
- log_ptr = mlog_open_and_write_index(mtr, page, index, type, 2);
+ log_ptr = mlog_open_and_write_index(mtr, rec, index, type, 2);
if (log_ptr) {
/* Write the parameter as a 2-byte ulint */
- mach_write_to_2(log_ptr, rec - page);
+ mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
mlog_close(mtr, log_ptr + 2);
}
}
@@ -679,6 +687,8 @@ page_parse_delete_rec_list(
return(ptr);
}
+ ut_ad(!!page_is_comp(page) == index->table->comp);
+
if (type == MLOG_LIST_END_DELETE
|| type == MLOG_COMP_LIST_END_DELETE) {
page_delete_rec_list_end(page, page + offset, index,
@@ -716,7 +726,7 @@ page_delete_rec_list_end(
ulint count;
ulint n_owned;
rec_t* sup;
- ibool comp;
+ ulint comp;
/* Reset the last insert info in the page header and increment
the modify clock for the frame */
@@ -731,12 +741,12 @@ page_delete_rec_list_end(
sup = page_get_supremum_rec(page);
- if (rec == page_get_infimum_rec(page)) {
+ comp = page_is_comp(page);
+ if (page_rec_is_infimum_low(rec - page)) {
rec = page_rec_get_next(rec);
}
- comp = page_is_comp(page);
- page_delete_rec_list_write_log(page, rec, index,
+ page_delete_rec_list_write_log(rec, index,
comp ? MLOG_COMP_LIST_END_DELETE : MLOG_LIST_END_DELETE, mtr);
if (rec == sup) {
@@ -772,7 +782,7 @@ page_delete_rec_list_end(
rec2 = page_rec_get_next(rec2);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -841,13 +851,15 @@ page_delete_rec_list_start(
byte type;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
- if (index->table->comp) {
+ ut_ad(!!page_is_comp(page) == index->table->comp);
+
+ if (page_is_comp(page)) {
type = MLOG_COMP_LIST_START_DELETE;
} else {
type = MLOG_LIST_START_DELETE;
}
- page_delete_rec_list_write_log(page, rec, index, type, mtr);
+ page_delete_rec_list_write_log(rec, index, type, mtr);
page_cur_set_before_first(page, &cur1);
@@ -868,7 +880,7 @@ page_delete_rec_list_start(
page_cur_delete_rec(&cur1, index, offsets, mtr);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -1221,7 +1233,7 @@ page_rec_get_n_recs_before(
rec_t* slot_rec;
page_t* page;
ulint i;
- ibool comp;
+ ulint comp;
lint n = 0;
ut_ad(page_rec_check(rec));
@@ -1264,9 +1276,9 @@ page_rec_print(
rec_t* rec, /* in: physical record */
const ulint* offsets)/* in: record descriptor */
{
- ibool comp = page_is_comp(buf_frame_align(rec));
+ ulint comp = page_is_comp(buf_frame_align(rec));
- ut_a(comp == rec_offs_comp(offsets));
+ ut_a(!comp == !rec_offs_comp(offsets));
rec_print_new(stderr, rec, offsets);
fprintf(stderr,
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
@@ -1335,7 +1347,7 @@ page_print_list(
ulint* offsets = offsets_;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
- ut_a(page_is_comp(page) == index->table->comp);
+ ut_a((ibool)!!page_is_comp(page) == index->table->comp);
fprintf(stderr,
"--------------------------------\n"
@@ -1381,7 +1393,7 @@ page_print_list(
"--------------------------------\n",
(ulong) (count + 1));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -1447,11 +1459,11 @@ page_rec_validate(
ulint n_owned;
ulint heap_no;
page_t* page;
- ibool comp;
+ ulint comp;
page = buf_frame_align(rec);
comp = page_is_comp(page);
- ut_a(comp == rec_offs_comp(offsets));
+ ut_a(!comp == !rec_offs_comp(offsets));
page_rec_check(rec);
rec_validate(rec, offsets);
@@ -1528,7 +1540,7 @@ page_simple_validate(
ulint count;
ulint own_count;
ibool ret = FALSE;
- ibool comp = page_is_comp(page);
+ ulint comp = page_is_comp(page);
/* Check first that the record heap and the directory do not
overlap. */
@@ -1725,11 +1737,11 @@ page_validate(
ulint n_slots;
ibool ret = FALSE;
ulint i;
- ibool comp = page_is_comp(page);
+ ulint comp = page_is_comp(page);
ulint* offsets = NULL;
ulint* old_offsets = NULL;
- if (comp != index->table->comp) {
+ if ((ibool)!!comp != index->table->comp) {
fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
goto func_exit2;
}
@@ -1743,9 +1755,7 @@ page_validate(
records in the page record heap do not overlap */
buf = mem_heap_alloc(heap, UNIV_PAGE_SIZE);
- for (i = 0; i < UNIV_PAGE_SIZE; i++) {
- buf[i] = 0;
- }
+ memset(buf, 0, UNIV_PAGE_SIZE);
/* Check first that the record heap and the directory do not
overlap. */
@@ -1810,8 +1820,7 @@ page_validate(
}
}
- if ((rec != page_get_supremum_rec(page))
- && (rec != page_get_infimum_rec(page))) {
+ if (page_rec_is_user_rec(rec)) {
data_size += rec_offs_size(offsets);
}
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index 74348b865a8..7c33476fb9e 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -320,7 +320,7 @@ cmp_data_data_slow(
|| (cur_type->mtype == DATA_BLOB
&& 0 == (cur_type->prtype & DATA_BINARY_TYPE)
&& dtype_get_charset_coll(cur_type->prtype) !=
- data_mysql_latin1_swedish_charset_coll)) {
+ DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
return(cmp_whole_field(cur_type,
data1, (unsigned) len1,
@@ -451,6 +451,20 @@ cmp_dtuple_rec_with_match(
ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
ut_ad(cur_field <= rec_offs_n_fields(offsets));
+ if (cur_bytes == 0 && cur_field == 0) {
+ ulint rec_info = rec_get_info_bits(rec,
+ rec_offs_comp(offsets));
+ ulint tup_info = dtuple_get_info_bits(dtuple);
+
+ if (rec_info & REC_INFO_MIN_REC_FLAG) {
+ ret = !(tup_info & REC_INFO_MIN_REC_FLAG);
+ goto order_resolved;
+ } else if (tup_info & REC_INFO_MIN_REC_FLAG) {
+ ret = -1;
+ goto order_resolved;
+ }
+ }
+
/* Match fields in a loop; stop if we run out of fields in dtuple
or find an externally stored field */
@@ -469,32 +483,7 @@ cmp_dtuple_rec_with_match(
the predefined minimum record, or the field is externally
stored */
- if (cur_bytes == 0) {
- if (cur_field == 0) {
-
- if (rec_get_info_bits(rec,
- rec_offs_comp(offsets))
- & REC_INFO_MIN_REC_FLAG) {
-
- if (dtuple_get_info_bits(dtuple)
- & REC_INFO_MIN_REC_FLAG) {
-
- ret = 0;
- } else {
- ret = 1;
- }
-
- goto order_resolved;
- }
-
- if (dtuple_get_info_bits(dtuple)
- & REC_INFO_MIN_REC_FLAG) {
- ret = -1;
-
- goto order_resolved;
- }
- }
-
+ if (UNIV_LIKELY(cur_bytes == 0)) {
if (rec_offs_nth_extern(offsets, cur_field)) {
/* We do not compare to an externally
stored field */
@@ -504,24 +493,20 @@ cmp_dtuple_rec_with_match(
goto order_resolved;
}
- if (dtuple_f_len == UNIV_SQL_NULL
- || rec_f_len == UNIV_SQL_NULL) {
-
- if (dtuple_f_len == rec_f_len) {
+ if (dtuple_f_len == UNIV_SQL_NULL) {
+ if (rec_f_len == UNIV_SQL_NULL) {
goto next_field;
}
- if (rec_f_len == UNIV_SQL_NULL) {
- /* We define the SQL null to be the
- smallest possible value of a field
- in the alphabetical order */
-
- ret = 1;
- } else {
- ret = -1;
- }
+ ret = -1;
+ goto order_resolved;
+ } else if (rec_f_len == UNIV_SQL_NULL) {
+ /* We define the SQL null to be the
+ smallest possible value of a field
+ in the alphabetical order */
+ ret = 1;
goto order_resolved;
}
}
@@ -530,7 +515,7 @@ cmp_dtuple_rec_with_match(
|| (cur_type->mtype == DATA_BLOB
&& 0 == (cur_type->prtype & DATA_BINARY_TYPE)
&& dtype_get_charset_coll(cur_type->prtype) !=
- data_mysql_latin1_swedish_charset_coll)) {
+ DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
ret = cmp_whole_field(
cur_type,
@@ -555,7 +540,7 @@ cmp_dtuple_rec_with_match(
/* Compare then the fields */
for (;;) {
- if (rec_f_len <= cur_bytes) {
+ if (UNIV_UNLIKELY(rec_f_len <= cur_bytes)) {
if (dtuple_f_len <= cur_bytes) {
goto next_field;
@@ -572,7 +557,7 @@ cmp_dtuple_rec_with_match(
rec_byte = *rec_b_ptr;
}
- if (dtuple_f_len <= cur_bytes) {
+ if (UNIV_UNLIKELY(dtuple_f_len <= cur_bytes)) {
dtuple_byte = dtype_get_pad_char(cur_type);
if (dtuple_byte == ULINT_UNDEFINED) {
@@ -600,14 +585,16 @@ cmp_dtuple_rec_with_match(
rec_byte = cmp_collate(rec_byte);
dtuple_byte = cmp_collate(dtuple_byte);
}
-
- if (dtuple_byte > rec_byte) {
- ret = 1;
- goto order_resolved;
- } else if (dtuple_byte < rec_byte) {
- ret = -1;
- goto order_resolved;
+ ret = dtuple_byte - rec_byte;
+ if (UNIV_UNLIKELY(ret)) {
+ if (ret < 0) {
+ ret = -1;
+ goto order_resolved;
+ } else {
+ ret = 1;
+ goto order_resolved;
+ }
}
next_byte:
/* Next byte */
@@ -740,7 +727,7 @@ cmp_rec_rec_with_match(
ulint cur_bytes; /* number of already matched bytes in current
field */
int ret = 3333; /* return value */
- ibool comp;
+ ulint comp;
ut_ad(rec1 && rec2 && index);
ut_ad(rec_offs_validate(rec1, index, offsets1));
@@ -832,7 +819,7 @@ cmp_rec_rec_with_match(
|| (cur_type->mtype == DATA_BLOB
&& 0 == (cur_type->prtype & DATA_BINARY_TYPE)
&& dtype_get_charset_coll(cur_type->prtype) !=
- data_mysql_latin1_swedish_charset_coll)) {
+ DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
ret = cmp_whole_field(cur_type,
rec1_b_ptr, (unsigned) rec1_f_len,
@@ -983,12 +970,8 @@ cmp_debug_dtuple_rec_with_match(
if (rec_get_info_bits(rec, rec_offs_comp(offsets))
& REC_INFO_MIN_REC_FLAG) {
- if (dtuple_get_info_bits(dtuple)
- & REC_INFO_MIN_REC_FLAG) {
- ret = 0;
- } else {
- ret = 1;
- }
+ ret = !(dtuple_get_info_bits(dtuple)
+ & REC_INFO_MIN_REC_FLAG);
goto order_resolved;
}
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 542c746209b..fbc33aea669 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -159,22 +159,20 @@ rec_init_offsets(
ulint* offsets)/* in/out: array of offsets;
in: n=rec_offs_n_fields(offsets) */
{
- ulint n_fields = rec_offs_n_fields(offsets);
ulint i = 0;
ulint offs;
rec_offs_make_valid(rec, index, offsets);
- if (index->table->comp) {
+ if (UNIV_LIKELY(index->table->comp)) {
const byte* nulls;
const byte* lens;
dict_field_t* field;
- dtype_t* type;
ulint null_mask;
ulint status = rec_get_status(rec);
ulint n_node_ptr_field = ULINT_UNDEFINED;
- switch (status) {
+ switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
/* the field is 8 bytes long */
@@ -196,56 +194,69 @@ rec_init_offsets(
null_mask = 1;
/* read the lengths of fields 0..n */
- for (; i < n_fields; i++) {
- ibool is_null = FALSE, is_external = FALSE;
+ do {
ulint len;
- if (i == n_node_ptr_field) {
- len = 4;
+ if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
+ len = offs += 4;
goto resolved;
}
field = dict_index_get_nth_field(index, i);
- type = dict_col_get_type(dict_field_get_col(field));
- if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
+ if (!(dtype_get_prtype(dict_col_get_type(
+ dict_field_get_col(field)))
+ & DATA_NOT_NULL)) {
/* nullable field => read the null flag */
- is_null = (*nulls & null_mask) != 0;
- null_mask <<= 1;
- if (null_mask == 0x100) {
+
+ if (UNIV_UNLIKELY(!(byte) null_mask)) {
nulls--;
null_mask = 1;
}
+
+ if (*nulls & null_mask) {
+ null_mask <<= 1;
+ /* No length is stored for NULL fields.
+ We do not advance offs, and we set
+ the length to zero and enable the
+ SQL NULL flag in offsets[]. */
+ len = offs | REC_OFFS_SQL_NULL;
+ goto resolved;
+ }
+ null_mask <<= 1;
}
- if (is_null) {
- /* No length is stored for NULL fields. */
- len = 0;
- } else if (!field->fixed_len) {
+ if (UNIV_UNLIKELY(!field->fixed_len)) {
/* Variable-length field: read the length */
+ dtype_t* type = dict_col_get_type(
+ dict_field_get_col(field));
len = *lens--;
- if (dtype_get_len(type) > 255
- || dtype_get_mtype(type) == DATA_BLOB) {
+ if (UNIV_UNLIKELY(dtype_get_len(type) > 255)
+ || UNIV_UNLIKELY(dtype_get_mtype(type)
+ == DATA_BLOB)) {
if (len & 0x80) {
/* 1exxxxxxx xxxxxxxx */
- is_external = !!(len & 0x40);
- len &= 0x3f;
len <<= 8;
len |= *lens--;
+
+ offs += len & 0x3fff;
+ if (UNIV_UNLIKELY(len
+ & 0x4000)) {
+ len = offs
+ | REC_OFFS_EXTERNAL;
+ } else {
+ len = offs;
+ }
+
+ goto resolved;
}
}
+
+ len = offs += len;
} else {
- len = field->fixed_len;
+ len = offs += field->fixed_len;
}
resolved:
- offs += len;
- len = offs;
- if (is_external) {
- len |= REC_OFFS_EXTERNAL;
- }
- if (is_null) {
- len |= REC_OFFS_SQL_NULL;
- }
rec_offs_base(offsets)[i + 1] = len;
- }
+ } while (++i < rec_offs_n_fields(offsets));
*rec_offs_base(offsets) =
(rec - (lens + 1)) | REC_OFFS_COMPACT;
@@ -253,22 +264,22 @@ rec_init_offsets(
/* Old-style record: determine extra size and end offsets */
offs = REC_N_OLD_EXTRA_BYTES;
if (rec_get_1byte_offs_flag(rec)) {
- offs += n_fields;
+ offs += rec_offs_n_fields(offsets);
*rec_offs_base(offsets) = offs;
/* Determine offsets to fields */
- for (; i < n_fields; i++) {
+ do {
offs = rec_1_get_field_end_info(rec, i);
if (offs & REC_1BYTE_SQL_NULL_MASK) {
offs &= ~REC_1BYTE_SQL_NULL_MASK;
offs |= REC_OFFS_SQL_NULL;
}
rec_offs_base(offsets)[1 + i] = offs;
- }
+ } while (++i < rec_offs_n_fields(offsets));
} else {
- offs += 2 * n_fields;
+ offs += 2 * rec_offs_n_fields(offsets);
*rec_offs_base(offsets) = offs;
/* Determine offsets to fields */
- for (; i < n_fields; i++) {
+ do {
offs = rec_2_get_field_end_info(rec, i);
if (offs & REC_2BYTE_SQL_NULL_MASK) {
offs &= ~REC_2BYTE_SQL_NULL_MASK;
@@ -279,7 +290,7 @@ rec_init_offsets(
offs |= REC_OFFS_EXTERNAL;
}
rec_offs_base(offsets)[1 + i] = offs;
- }
+ } while (++i < rec_offs_n_fields(offsets));
}
}
}
@@ -310,8 +321,9 @@ rec_get_offsets_func(
ut_ad(index);
ut_ad(heap);
- if (index->table->comp) {
- switch (rec_get_status(rec)) {
+ if (UNIV_LIKELY(index->table->comp)) {
+ switch (UNIV_EXPECT(rec_get_status(rec),
+ REC_STATUS_ORDINARY)) {
case REC_STATUS_ORDINARY:
n = dict_index_get_n_fields(index);
break;
@@ -331,13 +343,14 @@ rec_get_offsets_func(
n = rec_get_n_fields_old(rec);
}
- if (n_fields < n) {
+ if (UNIV_UNLIKELY(n_fields < n)) {
n = n_fields;
}
size = n + (1 + REC_OFFS_HEADER_SIZE);
- if (!offsets || rec_offs_get_n_alloc(offsets) < size) {
+ if (UNIV_UNLIKELY(!offsets) ||
+ UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
if (!*heap) {
*heap = mem_heap_create_func(size * sizeof(ulint),
NULL, MEM_HEAP_DYNAMIC, file, line);
@@ -588,30 +601,38 @@ rec_set_nth_field_extern_bit_new(
/* read the lengths of fields 0..n */
for (i = 0; i < n_fields; i++) {
- ibool is_null;
- ulint len;
field = dict_index_get_nth_field(index, i);
type = dict_col_get_type(dict_field_get_col(field));
- is_null = !(dtype_get_prtype(type) & DATA_NOT_NULL);
- if (is_null) {
- /* nullable field => read the null flag */
- is_null = !!(*nulls & null_mask);
+ if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
+ if (UNIV_UNLIKELY(!(byte) null_mask)) {
+ nulls--;
+ null_mask = 1;
+ }
+
+ if (*nulls & null_mask) {
+ null_mask <<= 1;
+ /* NULL fields cannot be external. */
+ ut_ad(i != ith);
+ continue;
+ }
+
null_mask <<= 1;
- if (null_mask == 0x100)
- nulls--, null_mask = 1;
}
- if (is_null || field->fixed_len) {
- /* No length (or extern bit) is stored for
- fields that are NULL or fixed-length. */
+ if (field->fixed_len) {
+ /* fixed-length fields cannot be external
+ (Fixed-length fields longer than
+ DICT_MAX_COL_PREFIX_LEN will be treated as
+ variable-length ones in dict_index_add_col().) */
ut_ad(i != ith);
continue;
}
- len = *lens--;
+ lens--;
if (dtype_get_len(type) > 255
|| dtype_get_mtype(type) == DATA_BLOB) {
+ ulint len = lens[1];
if (len & 0x80) { /* 1exxxxxx: 2-byte length */
if (i == ith) {
- if (!val == !(len & 0x20)) {
+ if (!val == !(len & 0x40)) {
return; /* no change */
}
/* toggle the extern bit */
@@ -652,9 +673,17 @@ rec_set_field_extern_bits(
to log about the change */
{
ulint i;
-
- for (i = 0; i < n_fields; i++) {
- rec_set_nth_field_extern_bit(rec, index, vec[i], TRUE, mtr);
+
+ if (UNIV_LIKELY(index->table->comp)) {
+ for (i = 0; i < n_fields; i++) {
+ rec_set_nth_field_extern_bit_new(rec, index, vec[i],
+ TRUE, mtr);
+ }
+ } else {
+ for (i = 0; i < n_fields; i++) {
+ rec_set_nth_field_extern_bit_old(rec, vec[i],
+ TRUE, mtr);
+ }
}
}
@@ -802,6 +831,7 @@ rec_convert_dtuple_to_rec_new(
byte* lens;
ulint len;
ulint i;
+ ulint n_node_ptr_field;
ulint fixed_len;
ulint null_mask = 1;
const ulint n_fields = dtuple_get_n_fields(dtuple);
@@ -810,16 +840,26 @@ rec_convert_dtuple_to_rec_new(
ut_ad(index->table->comp);
ut_ad(n_fields > 0);
- switch (status) {
+
+ /* Try to ensure that the memset() between the for() loops
+ completes fast. The address is not exact, but UNIV_PREFETCH
+ should never generate a memory fault. */
+ UNIV_PREFETCH_RW(rec - REC_N_NEW_EXTRA_BYTES - n_fields);
+ UNIV_PREFETCH_RW(rec);
+
+ switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
case REC_STATUS_ORDINARY:
ut_ad(n_fields <= dict_index_get_n_fields(index));
+ n_node_ptr_field = ULINT_UNDEFINED;
break;
case REC_STATUS_NODE_PTR:
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
+ n_node_ptr_field = n_fields - 1;
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
ut_ad(n_fields == 1);
+ n_node_ptr_field = ULINT_UNDEFINED;
goto init;
default:
ut_a(0);
@@ -831,15 +871,18 @@ rec_convert_dtuple_to_rec_new(
rec += (index->n_nullable + 7) / 8;
for (i = 0; i < n_fields; i++) {
+ if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
+#ifdef UNIV_DEBUG
+ field = dtuple_get_nth_field(dtuple, i);
+ type = dfield_get_type(field);
+ ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
+ ut_ad(dfield_get_len(field) == 4);
+#endif /* UNIV_DEBUG */
+ goto init;
+ }
field = dtuple_get_nth_field(dtuple, i);
type = dfield_get_type(field);
len = dfield_get_len(field);
- if (status == REC_STATUS_NODE_PTR && i == n_fields - 1) {
- fixed_len = 4;
- ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
- ut_ad(len == 4);
- continue;
- }
fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
@@ -881,27 +924,33 @@ init:
type = dfield_get_type(field);
len = dfield_get_len(field);
- if (status == REC_STATUS_NODE_PTR && i == n_fields - 1) {
- fixed_len = 4;
+ if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
ut_ad(len == 4);
- goto copy;
+ memcpy(end, dfield_get_data(field), len);
+ break;
}
fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
/* nullable field */
ut_ad(index->n_nullable > 0);
+
+ if (UNIV_UNLIKELY(!(byte) null_mask)) {
+ nulls--;
+ null_mask = 1;
+ }
+
ut_ad(*nulls < null_mask);
+
/* set the null flag if necessary */
if (len == UNIV_SQL_NULL) {
*nulls |= null_mask;
+ null_mask <<= 1;
+ continue;
}
+
null_mask <<= 1;
- if (null_mask == 0x100)
- nulls--, null_mask = 1;
- if (len == UNIV_SQL_NULL)
- continue;
}
/* only nullable fields can be null */
ut_ad(len != UNIV_SQL_NULL);
@@ -921,7 +970,7 @@ init:
*lens-- = (byte) len;
}
}
- copy:
+
memcpy(end, dfield_get_data(field), len);
end += len;
}
@@ -949,7 +998,7 @@ rec_convert_dtuple_to_rec(
ut_ad(dtuple_validate(dtuple));
ut_ad(dtuple_check_typed(dtuple));
- if (index->table->comp) {
+ if (UNIV_LIKELY(index->table->comp)) {
rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
} else {
rec = rec_convert_dtuple_to_rec_old(buf, dtuple);
@@ -965,7 +1014,7 @@ rec_convert_dtuple_to_rec(
offsets = rec_get_offsets(rec, index,
offsets_, ULINT_UNDEFINED, &heap);
ut_ad(rec_validate(rec, offsets));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -1078,17 +1127,18 @@ rec_copy_prefix_to_buf(
for the copied prefix, or NULL */
ulint* buf_size) /* in/out: buffer size */
{
- byte* nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
- byte* lens = nulls - (index->n_nullable + 7) / 8;
+ byte* nulls;
+ byte* lens;
dict_field_t* field;
dtype_t* type;
ulint i;
- ulint prefix_len = 0;
- ibool is_null;
- ulint null_mask = 1;
+ ulint prefix_len;
+ ulint null_mask;
ulint status;
- if (!index->table->comp) {
+ UNIV_PREFETCH_RW(*buf);
+
+ if (UNIV_UNLIKELY(!index->table->comp)) {
ut_ad(rec_validate_old(rec));
return(rec_copy_prefix_to_buf_old(rec, n_fields,
rec_get_field_start_offs(rec, n_fields),
@@ -1109,25 +1159,36 @@ rec_copy_prefix_to_buf(
case REC_STATUS_SUPREMUM:
/* infimum or supremum record: no sense to copy anything */
default:
- ut_a(0);
+ ut_error;
return(NULL);
}
+ nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
+ lens = nulls - (index->n_nullable + 7) / 8;
+ UNIV_PREFETCH_R(lens);
+ prefix_len = 0;
+ null_mask = 1;
+
/* read the lengths of fields 0..n */
for (i = 0; i < n_fields; i++) {
field = dict_index_get_nth_field(index, i);
type = dict_col_get_type(dict_field_get_col(field));
- is_null = !(dtype_get_prtype(type) & DATA_NOT_NULL);
- if (is_null) {
+ if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
/* nullable field => read the null flag */
- is_null = !!(*nulls & null_mask);
+ if (UNIV_UNLIKELY(!(byte) null_mask)) {
+ nulls--;
+ null_mask = 1;
+ }
+
+ if (*nulls & null_mask) {
+ null_mask <<= 1;
+ continue;
+ }
+
null_mask <<= 1;
- if (null_mask == 0x100)
- nulls--, null_mask = 1;
}
- if (is_null) {
- } else if (field->fixed_len) {
+ if (field->fixed_len) {
prefix_len += field->fixed_len;
} else {
ulint len = *lens--;
@@ -1138,12 +1199,15 @@ rec_copy_prefix_to_buf(
len &= 0x3f;
len <<= 8;
len |= *lens--;
+ UNIV_PREFETCH_R(lens);
}
}
prefix_len += len;
}
}
+ UNIV_PREFETCH_R(rec + prefix_len);
+
prefix_len += rec - (lens + 1);
if ((*buf == NULL) || (*buf_size < prefix_len)) {
@@ -1412,7 +1476,7 @@ rec_print(
rec_print_new(file, rec, rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 303fe5749bc..bce775c25d6 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -478,7 +478,7 @@ row_ins_cascade_calc_update_vec(
if (parent_ufield->field_no == parent_field_no) {
- ulint fixed_size;
+ ulint min_size;
/* A field in the parent index record is
updated. Let us make the update vector
@@ -508,10 +508,13 @@ row_ins_cascade_calc_update_vec(
column, do not allow the update */
if (ufield->new_val.len != UNIV_SQL_NULL
- && ufield->new_val.len
- > dtype_get_len(type)) {
+ && dtype_get_at_most_n_mbchars(
+ type, dtype_get_len(type),
+ ufield->new_val.len,
+ ufield->new_val.data)
+ < ufield->new_val.len) {
- return(ULINT_UNDEFINED);
+ return(ULINT_UNDEFINED);
}
/* If the parent column type has a different
@@ -519,29 +522,48 @@ row_ins_cascade_calc_update_vec(
need to pad with spaces the new value of the
child column */
- fixed_size = dtype_get_fixed_size(type);
-
- /* TODO: pad in UCS-2 with 0x0020.
- TODO: How does the special truncation of
- UTF-8 CHAR cols affect this? */
+ min_size = dtype_get_min_size(type);
- if (fixed_size
+ if (min_size
&& ufield->new_val.len != UNIV_SQL_NULL
- && ufield->new_val.len < fixed_size) {
+ && ufield->new_val.len < min_size) {
+ char* pad_start;
+ const char* pad_end;
ufield->new_val.data =
mem_heap_alloc(heap,
- fixed_size);
- ufield->new_val.len = fixed_size;
- ut_a(dtype_get_pad_char(type)
- != ULINT_UNDEFINED);
-
- memset(ufield->new_val.data,
- (byte)dtype_get_pad_char(type),
- fixed_size);
+ min_size);
+ pad_start =
+ ((char*) ufield->new_val.data)
+ + ufield->new_val.len;
+ pad_end =
+ ((char*) ufield->new_val.data)
+ + min_size;
+ ufield->new_val.len = min_size;
ut_memcpy(ufield->new_val.data,
parent_ufield->new_val.data,
parent_ufield->new_val.len);
+
+ switch (UNIV_EXPECT(
+ dtype_get_mbminlen(type), 1)) {
+ default:
+ ut_error;
+ case 1:
+ /* space=0x20 */
+ memset(pad_start, 0x20,
+ pad_end - pad_start);
+ break;
+ case 2:
+ /* space=0x0020 */
+ ut_a(!(ufield->new_val.len
+ % 2));
+ ut_a(!(min_size % 2));
+ do {
+ *pad_start++ = 0x00;
+ *pad_start++ = 0x20;
+ } while (pad_start < pad_end);
+ break;
+ }
}
ufield->extern_storage = FALSE;
@@ -1255,9 +1277,11 @@ run_again:
/* Scan index records and check if there is a matching record */
for (;;) {
+ page_t* page;
rec = btr_pcur_get_rec(&pcur);
+ page = buf_frame_align(rec);
- if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
+ if (rec == page_get_infimum_rec(page)) {
goto next_rec;
}
@@ -1265,7 +1289,7 @@ run_again:
offsets = rec_get_offsets(rec, check_index,
offsets, ULINT_UNDEFINED, &heap);
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
+ if (rec == page_get_supremum_rec(page)) {
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec,
check_index, offsets, thr);
@@ -1392,7 +1416,7 @@ do_possible_lock_wait:
}
exit_func:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -1529,12 +1553,7 @@ row_ins_dupl_error_with_rec(
}
}
- if (!rec_get_deleted_flag(rec, index->table->comp)) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
}
/*******************************************************************
@@ -1561,7 +1580,6 @@ row_ins_scan_sec_index_for_duplicate(
ulint err = DB_SUCCESS;
ibool moved;
mtr_t mtr;
- trx_t* trx;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -1601,11 +1619,6 @@ row_ins_scan_sec_index_for_duplicate(
goto next_rec;
}
- /* Try to place a lock on the index record */
-
- trx = thr_get_trx(thr);
- ut_ad(trx);
-
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
@@ -1629,7 +1642,7 @@ row_ins_scan_sec_index_for_duplicate(
break;
}
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
+ if (page_rec_is_supremum(rec)) {
goto next_rec;
}
@@ -1660,7 +1673,7 @@ next_rec:
}
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
mtr_commit(&mtr);
@@ -1697,7 +1710,6 @@ row_ins_duplicate_error_in_clust(
#ifndef UNIV_HOTBACKUP
ulint err;
rec_t* rec;
- page_t* page;
ulint n_unique;
trx_t* trx = thr_get_trx(thr);
mem_heap_t*heap = NULL;
@@ -1728,9 +1740,8 @@ row_ins_duplicate_error_in_clust(
if (cursor->low_match >= n_unique) {
rec = btr_cur_get_rec(cursor);
- page = buf_frame_align(rec);
- if (rec != page_get_infimum_rec(page)) {
+ if (!page_rec_is_infimum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
@@ -1772,9 +1783,8 @@ row_ins_duplicate_error_in_clust(
if (cursor->up_match >= n_unique) {
rec = page_rec_get_next(btr_cur_get_rec(cursor));
- page = buf_frame_align(rec);
- if (rec != page_get_supremum_rec(page)) {
+ if (!page_rec_is_supremum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
@@ -1842,7 +1852,6 @@ row_ins_must_modify(
{
ulint enough_match;
rec_t* rec;
- page_t* page;
/* NOTE: (compare to the note in row_ins_duplicate_error) Because node
pointers on upper levels of the B-tree may match more to entry than
@@ -1856,9 +1865,8 @@ row_ins_must_modify(
if (cursor->low_match >= enough_match) {
rec = btr_cur_get_rec(cursor);
- page = buf_frame_align(rec);
- if (rec != page_get_infimum_rec(page)) {
+ if (!page_rec_is_infimum(rec)) {
return(ROW_INS_PREV);
}
@@ -1897,7 +1905,6 @@ row_ins_index_entry_low(
ulint modify = 0; /* remove warning */
rec_t* insert_rec;
rec_t* rec;
- rec_t* first_rec;
ulint err;
ulint n_unique;
big_rec_t* big_rec = NULL;
@@ -1932,15 +1939,20 @@ row_ins_index_entry_low(
err = DB_SUCCESS;
goto function_exit;
- }
-
- first_rec = page_rec_get_next(page_get_infimum_rec(
- buf_frame_align(btr_cur_get_rec(&cursor))));
+ }
+
+#ifdef UNIV_DEBUG
+ {
+ page_t* page = btr_cur_get_page(&cursor);
+ rec_t* first_rec = page_rec_get_next(
+ page_get_infimum_rec(page));
- if (!page_rec_is_supremum(first_rec)) {
- ut_a(rec_get_n_fields(first_rec, index)
+ if (UNIV_LIKELY(first_rec != page_get_supremum_rec(page))) {
+ ut_a(rec_get_n_fields(first_rec, index)
== dtuple_get_n_fields(entry));
+ }
}
+#endif
n_unique = dict_index_get_n_unique(index);
@@ -2048,7 +2060,7 @@ function_exit:
mtr_commit(&mtr);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index fafbef4c999..2ac0824b331 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -265,7 +265,7 @@ row_mysql_store_col_in_innobase_format(
necessarily the length of the actual
payload data; if the column is a true
VARCHAR then this is irrelevant */
- ibool comp) /* in: TRUE = compact format */
+ ulint comp) /* in: nonzero=compact format */
{
byte* ptr = mysql_data;
dtype_t* dtype;
@@ -971,25 +971,6 @@ run_again:
}
/*************************************************************************
-Unlocks all table locks explicitly requested by trx (with LOCK TABLES,
-lock type LOCK_TABLE_EXP). */
-
-void
-row_unlock_tables_for_mysql(
-/*========================*/
- trx_t* trx) /* in: transaction */
-{
- if (!trx->n_lock_table_exp) {
-
- return;
- }
-
- mutex_enter(&kernel_mutex);
- lock_release_tables_off_kernel(trx);
- mutex_exit(&kernel_mutex);
-}
-
-/*************************************************************************
Sets a table lock on the table mentioned in prebuilt. */
int
@@ -1000,9 +981,10 @@ row_lock_table_for_mysql(
table handle */
dict_table_t* table, /* in: table to lock, or NULL
if prebuilt->table should be
- locked or a
+ locked as
prebuilt->select_lock_type */
- ulint mode) /* in: lock mode of table */
+ ulint mode) /* in: lock mode of table
+ (ignored if table==NULL) */
{
trx_t* trx = prebuilt->trx;
que_thr_t* thr;
@@ -1038,14 +1020,8 @@ run_again:
if (table) {
err = lock_table(0, table, mode, thr);
} else {
- if (mode == LOCK_TABLE_TRANSACTIONAL) {
- err = lock_table(LOCK_TABLE_TRANSACTIONAL,
- prebuilt->table,
- prebuilt->select_lock_type, thr);
- } else {
- err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
- prebuilt->select_lock_type, thr);
- }
+ err = lock_table(0, prebuilt->table,
+ prebuilt->select_lock_type, thr);
}
trx->error_state = err;
@@ -1453,51 +1429,106 @@ run_again:
}
/*************************************************************************
-Does an unlock of a row for MySQL. */
+This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
+calling this function we must use trx_reset_new_rec_lock_info() and
+trx_register_new_rec_lock() to store the information which new record locks
+really were set. This function removes a newly set lock under prebuilt->pcur,
+and also under prebuilt->clust_pcur. Currently, this is only used and tested
+in the case of an UPDATE or a DELETE statement, where the row lock is of the
+LOCK_X type.
+Thus, this implements a 'mini-rollback' that releases the latest record
+locks we set. */
int
row_unlock_for_mysql(
/*=================*/
/* out: error code or DB_SUCCESS */
- row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
+ row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
handle */
+ ibool has_latches_on_recs)/* TRUE if called so that we have
+ the latches on the records under pcur
+ and clust_pcur, and we do not need to
+ reposition the cursors. */
{
- rec_t* rec;
- btr_pcur_t* cur = prebuilt->pcur;
+ dict_index_t* index;
+ btr_pcur_t* pcur = prebuilt->pcur;
+ btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
trx_t* trx = prebuilt->trx;
+ rec_t* rec;
mtr_t mtr;
ut_ad(prebuilt && trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
-
+
+ if (!srv_locks_unsafe_for_binlog) {
+
+ fprintf(stderr,
+"InnoDB: Error: calling row_unlock_for_mysql though\n"
+"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n");
+
+ return(DB_SUCCESS);
+ }
+
trx->op_info = "unlock_row";
-
- if (srv_locks_unsafe_for_binlog) {
- if (trx->trx_create_lock == TRUE) {
- mtr_start(&mtr);
+ index = btr_pcur_get_btr_cur(pcur)->index;
+
+ if (index != NULL && trx_new_rec_locks_contain(trx, index)) {
+
+ mtr_start(&mtr);
- /* Restore a cursor position and find a record */
- btr_pcur_restore_position(BTR_SEARCH_LEAF, cur, &mtr);
- rec = btr_pcur_get_rec(cur);
+ /* Restore the cursor position and find the record */
+
+ if (!has_latches_on_recs) {
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
+ }
- if (rec) {
+ rec = btr_pcur_get_rec(pcur);
- lock_rec_reset_and_release_wait(rec);
- } else {
- fputs("InnoDB: Error: "
- "Record for the lock not found\n",
- stderr);
- mem_analyze_corruption((byte*) trx);
- ut_error;
- }
+ mutex_enter(&kernel_mutex);
- trx->trx_create_lock = FALSE;
- mtr_commit(&mtr);
+ lock_rec_reset_and_release_wait(rec);
+
+ mutex_exit(&kernel_mutex);
+
+ mtr_commit(&mtr);
+
+ /* If the search was done through the clustered index, then
+ we have not used clust_pcur at all, and we must NOT try to
+ reset locks on clust_pcur. The values in clust_pcur may be
+ garbage! */
+
+ if (index->type & DICT_CLUSTERED) {
+
+ goto func_exit;
}
-
}
+
+ index = btr_pcur_get_btr_cur(clust_pcur)->index;
+
+ if (index != NULL && trx_new_rec_locks_contain(trx, index)) {
+
+ mtr_start(&mtr);
+ /* Restore the cursor position and find the record */
+
+ if (!has_latches_on_recs) {
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, clust_pcur,
+ &mtr);
+ }
+
+ rec = btr_pcur_get_rec(clust_pcur);
+
+ mutex_enter(&kernel_mutex);
+
+ lock_rec_reset_and_release_wait(rec);
+
+ mutex_exit(&kernel_mutex);
+
+ mtr_commit(&mtr);
+ }
+
+func_exit:
trx->op_info = "";
return(DB_SUCCESS);
@@ -3858,7 +3889,7 @@ funct_exit:
que_graph_free(graph);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -3893,6 +3924,7 @@ row_scan_and_check_index(
int cmp;
ibool contains_null;
ulint i;
+ ulint cnt;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -3915,11 +3947,19 @@ row_scan_and_check_index(
dtuple_set_n_fields(prebuilt->search_tuple, 0);
prebuilt->select_lock_type = LOCK_NONE;
+ cnt = 1000;
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
loop:
+ /* Check thd->killed every 1,000 scanned rows */
+ if (--cnt == 0) {
+ if (trx_is_interrupted(prebuilt->trx)) {
+ goto func_exit;
+ }
+ cnt = 1000;
+ }
if (ret != DB_SUCCESS) {
-
+ func_exit:
mem_free(buf);
mem_heap_free(heap);
@@ -4046,7 +4086,7 @@ row_check_table_for_mysql(
ut_print_name(stderr, index->name);
putc('\n', stderr); */
- if (!btr_validate_tree(index->tree)) {
+ if (!btr_validate_tree(index->tree, prebuilt->trx)) {
ret = DB_ERROR;
} else {
if (!row_scan_and_check_index(prebuilt,
@@ -4054,6 +4094,10 @@ row_check_table_for_mysql(
ret = DB_ERROR;
}
+ if (trx_is_interrupted(prebuilt->trx)) {
+ break;
+ }
+
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
index->name); */
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index 5893e016011..abcf97110d9 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -126,7 +126,7 @@ row_purge_remove_clust_if_poss_low(
if (0 != ut_dulint_cmp(node->roll_ptr,
row_get_rec_roll_ptr(rec, index, rec_get_offsets(
rec, index, offsets_, ULINT_UNDEFINED, &heap)))) {
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
/* Someone else has modified the record later: do not remove */
@@ -135,7 +135,7 @@ row_purge_remove_clust_if_poss_low(
return(TRUE);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c
index a6d3f1d5ab0..9a74397dc08 100644
--- a/innobase/row/row0row.c
+++ b/innobase/row/row0row.c
@@ -535,7 +535,7 @@ row_build_row_ref_in_tuple(
}
ut_ad(dtuple_check_typed(ref));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -616,7 +616,6 @@ row_search_on_row_ref(
ulint low_match;
rec_t* rec;
dict_index_t* index;
- page_t* page;
ut_ad(dtuple_check_typed(ref));
@@ -629,9 +628,8 @@ row_search_on_row_ref(
low_match = btr_pcur_get_low_match(pcur);
rec = btr_pcur_get_rec(pcur);
- page = buf_frame_align(rec);
- if (rec == page_get_infimum_rec(page)) {
+ if (page_rec_is_infimum(rec)) {
return(FALSE);
}
@@ -702,7 +700,6 @@ row_search_index_entry(
{
ulint n_fields;
ulint low_match;
- page_t* page;
rec_t* rec;
ut_ad(dtuple_check_typed(entry));
@@ -711,11 +708,10 @@ row_search_index_entry(
low_match = btr_pcur_get_low_match(pcur);
rec = btr_pcur_get_rec(pcur);
- page = buf_frame_align(rec);
n_fields = dtuple_get_n_fields(entry);
- if (rec == page_get_infimum_rec(page)) {
+ if (page_rec_is_infimum(rec)) {
return(FALSE);
}
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index 94cf82d6a3d..15439bed7e7 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -125,7 +125,7 @@ row_sel_sec_rec_is_for_clust_rec(
}
func_exit:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(is_equal);
@@ -630,6 +630,8 @@ row_sel_get_clust_rec(
ulint* offsets = offsets_;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ *out_rec = NULL;
+
offsets = rec_get_offsets(rec,
btr_pcur_get_btr_cur(&plan->pcur)->index,
offsets, ULINT_UNDEFINED, &heap);
@@ -663,8 +665,6 @@ row_sel_get_clust_rec(
clustered index record did not exist in the read view of
trx. */
- clust_rec = NULL;
-
goto func_exit;
}
@@ -733,7 +733,6 @@ row_sel_get_clust_rec(
if ((old_vers || rec_get_deleted_flag(rec, plan->table->comp))
&& !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
clust_rec, index)) {
- clust_rec = NULL;
goto func_exit;
}
}
@@ -742,11 +741,11 @@ row_sel_get_clust_rec(
row_sel_fetch_columns(index, clust_rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
-func_exit:
*out_rec = clust_rec;
+func_exit:
err = DB_SUCCESS;
err_exit:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -1066,7 +1065,7 @@ row_sel_try_search_shortcut(
plan->n_rows_fetched++;
func_exit:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(SEL_FOUND);
@@ -1261,7 +1260,7 @@ rec_loop:
/* PHASE 1: Set a lock if specified */
if (!node->asc && cursor_just_opened
- && (rec != page_get_supremum_rec(buf_frame_align(rec)))) {
+ && !page_rec_is_supremum(rec)) {
/* When we open a cursor for a descending search, we must set
a next-key lock on the successor record: otherwise it would
@@ -1299,7 +1298,7 @@ rec_loop:
}
}
- if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
+ if (page_rec_is_infimum(rec)) {
/* The infimum record on a page cannot be in the result set,
and neither can a record lock be placed on it: we skip such
@@ -1337,7 +1336,7 @@ rec_loop:
}
}
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
+ if (page_rec_is_supremum(rec)) {
/* A page supremum record cannot be in the result set: skip
it now when we have placed a possible lock on it */
@@ -1780,7 +1779,7 @@ lock_wait_or_error:
ut_ad(sync_thread_levels_empty_gen(TRUE));
func_exit:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -2416,14 +2415,12 @@ row_sel_store_mysql_rec(
mem_heap_t* extern_field_heap = NULL;
byte* data;
ulint len;
- byte* blob_buf;
- int pad_char;
ulint i;
ut_ad(prebuilt->mysql_template);
ut_ad(rec_offs_validate(rec, NULL, offsets));
- if (prebuilt->blob_heap != NULL) {
+ if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
@@ -2435,7 +2432,8 @@ row_sel_store_mysql_rec(
data = rec_get_nth_field(rec, offsets,
templ->rec_field_no, &len);
- if (rec_offs_nth_extern(offsets, templ->rec_field_no)) {
+ if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
+ templ->rec_field_no))) {
/* Copy an externally stored field to the temporary
heap */
@@ -2456,7 +2454,7 @@ row_sel_store_mysql_rec(
}
if (len != UNIV_SQL_NULL) {
- if (templ->type == DATA_BLOB) {
+ if (UNIV_UNLIKELY(templ->type == DATA_BLOB)) {
ut_a(prebuilt->templ_contains_blob);
@@ -2465,8 +2463,9 @@ row_sel_store_mysql_rec(
of 1000000 bytes. Since the test takes some
CPU time, we do not use it for small BLOBs. */
- if (len > 2000000
- && !ut_test_malloc(len + 1000000)) {
+ if (UNIV_UNLIKELY(len > 2000000)
+ && UNIV_UNLIKELY(!ut_test_malloc(
+ len + 1000000))) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -2492,11 +2491,9 @@ row_sel_store_mysql_rec(
mem_heap_create(len);
}
- blob_buf = mem_heap_alloc(prebuilt->blob_heap,
- len);
- ut_memcpy(blob_buf, data, len);
-
- data = blob_buf;
+ data = memcpy(mem_heap_alloc(
+ prebuilt->blob_heap, len),
+ data, len);
}
row_sel_field_store_in_mysql_format(
@@ -2521,41 +2518,45 @@ row_sel_store_mysql_rec(
account caused seg faults with NULL BLOB fields, and
bug number 154 in the MySQL bug database: GROUP BY
and DISTINCT could treat NULL values inequal. */
+ int pad_char;
mysql_rec[templ->mysql_null_byte_offset] |=
(byte) (templ->mysql_null_bit_mask);
- if (templ->type == DATA_VARCHAR
- || templ->type == DATA_CHAR
- || templ->type == DATA_BINARY
- || templ->type == DATA_FIXBINARY
- || templ->type == DATA_MYSQL
- || templ->type == DATA_VARMYSQL) {
+ switch (templ->type) {
+ case DATA_VARCHAR:
+ case DATA_CHAR:
+ case DATA_BINARY:
+ case DATA_FIXBINARY:
+ case DATA_MYSQL:
+ case DATA_VARMYSQL:
/* MySQL pads all non-BLOB and non-TEXT
string types with space ' ' */
-
- pad_char = ' ';
- } else {
- pad_char = '\0';
+ if (UNIV_UNLIKELY(templ->mbminlen == 2)) {
+ /* Treat UCS2 as a special case. */
+ data = mysql_rec
+ + templ->mysql_col_offset;
+ len = templ->mysql_col_len;
+ /* There are two UCS2 bytes per char,
+ so the length has to be even. */
+ ut_a(!(len & 1));
+ /* Pad with 0x0020. */
+ while (len) {
+ *data++ = 0x00;
+ *data++ = 0x20;
+ len -= 2;
+ }
+ continue;
+ }
+ pad_char = 0x20;
+ break;
+ default:
+ pad_char = 0x00;
+ break;
}
- /* Handle UCS2 strings differently. */
- if (pad_char != '\0' && templ->mbminlen == 2) {
- /* There are two bytes per char, so the length
- has to be an even number. */
- ut_a(!(templ->mysql_col_len & 1));
- data = mysql_rec + templ->mysql_col_offset;
- len = templ->mysql_col_len;
- /* Pad with 0x0020. */
- while (len >= 2) {
- *data++ = 0x00;
- *data++ = 0x20;
- len -= 2;
- }
- } else {
- ut_ad(!pad_char || templ->mbminlen == 1);
- memset(mysql_rec + templ->mysql_col_offset,
+ ut_ad(!pad_char || templ->mbminlen == 1);
+ memset(mysql_rec + templ->mysql_col_offset,
pad_char, templ->mysql_col_len);
- }
}
}
@@ -2783,6 +2784,10 @@ sel_restore_position_for_mysql(
process the record the cursor is
now positioned on (i.e. we should
not go to the next record yet) */
+ ibool* same_user_rec, /* out: TRUE if we were able to restore
+ the cursor on a user record with the
+ same ordering prefix in in the
+ B-tree index */
ulint latch_mode, /* in: latch mode wished in
restoration */
btr_pcur_t* pcur, /* in: cursor whose position
@@ -2799,6 +2804,8 @@ sel_restore_position_for_mysql(
success = btr_pcur_restore_position(latch_mode, pcur, mtr);
+ *same_user_rec = success;
+
if (relative_position == BTR_PCUR_ON) {
if (success) {
return(FALSE);
@@ -2849,8 +2856,9 @@ row_sel_pop_cached_row_for_mysql(
mysql_row_templ_t* templ;
byte* cached_rec;
ut_ad(prebuilt->n_fetch_cached > 0);
+ ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
- if (prebuilt->keep_other_fields_on_keyread)
+ if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread))
{
/* Copy cache record field by field, don't touch fields that
are not covered by current key */
@@ -2877,7 +2885,7 @@ row_sel_pop_cached_row_for_mysql(
else
{
ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
- prebuilt->mysql_row_len);
+ prebuilt->mysql_prefix_len);
}
prebuilt->n_fetch_cached--;
prebuilt->fetch_cache_first++;
@@ -2925,9 +2933,9 @@ row_sel_push_cache_row_for_mysql(
ut_ad(prebuilt->fetch_cache_first == 0);
- if (!row_sel_store_mysql_rec(
+ if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
prebuilt->fetch_cache[prebuilt->n_fetch_cached],
- prebuilt, rec, offsets)) {
+ prebuilt, rec, offsets))) {
ut_error;
}
@@ -3048,11 +3056,7 @@ row_search_for_mysql(
rec_t* index_rec;
rec_t* clust_rec;
rec_t* old_vers;
- ulint err = DB_SUCCESS;
- ibool moved;
- ibool cons_read_requires_clust_rec;
- ibool was_lock_wait;
- ulint shortcut;
+ ulint err = DB_SUCCESS;
ibool unique_search = FALSE;
ibool unique_search_from_clust_index = FALSE;
ibool mtr_has_extra_clust_latch = FALSE;
@@ -3062,20 +3066,22 @@ row_search_for_mysql(
locking SELECT, and the isolation
level is <= TRX_ISO_READ_COMMITTED,
then this is set to FALSE */
- ibool success;
- ibool comp;
+#ifdef UNIV_SEARCH_DEBUG
ulint cnt = 0;
+#endif /* UNIV_SEARCH_DEBUG */
ulint next_offs;
+ ibool same_user_rec;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
+
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
ut_ad(index && pcur && search_tuple);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
- if (prebuilt->table->ibd_file_missing) {
+ if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error:\n"
"InnoDB: MySQL is trying to use a table handle but the .ibd file for\n"
@@ -3089,7 +3095,7 @@ row_search_for_mysql(
return(DB_ERROR);
}
- if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name ",
@@ -3103,7 +3109,7 @@ row_search_for_mysql(
}
if (trx->n_mysql_tables_in_use == 0
- && prebuilt->select_lock_type == LOCK_NONE) {
+ && UNIV_UNLIKELY(prebuilt->select_lock_type == LOCK_NONE)) {
/* Note that if MySQL uses an InnoDB temp table that it
created inside LOCK TABLES, then n_mysql_tables_in_use can
be zero; in that case select_lock_type is set to LOCK_X in
@@ -3126,8 +3132,8 @@ row_search_for_mysql(
/* PHASE 0: Release a possible s-latch we are holding on the
adaptive hash index latch if there is someone waiting behind */
- if (trx->has_search_latch
- && btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
+ if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED)
+ && trx->has_search_latch) {
/* There is an x-latch request on the adaptive hash index:
release the s-latch to reduce starvation and wait for
@@ -3140,10 +3146,20 @@ row_search_for_mysql(
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
}
+ /* Reset the new record lock info if we srv_locks_unsafe_for_binlog
+ is set. Then we are able to remove the record locks set here on an
+ individual row. */
+
+ if (srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
+
+ trx_reset_new_rec_lock_info(trx);
+ }
+
/*-------------------------------------------------------------*/
/* PHASE 1: Try to pop the row from the prefetch cache */
- if (direction == 0) {
+ if (UNIV_UNLIKELY(direction == 0)) {
trx->op_info = "starting index read";
prebuilt->n_rows_fetched = 0;
@@ -3161,8 +3177,8 @@ row_search_for_mysql(
prebuilt->fetch_direction = direction;
}
- if (direction != prebuilt->fetch_direction) {
- if (prebuilt->n_fetch_cached > 0) {
+ if (UNIV_UNLIKELY(direction != prebuilt->fetch_direction)) {
+ if (UNIV_UNLIKELY(prebuilt->n_fetch_cached > 0)) {
ut_error;
/* TODO: scrollable cursor: restore cursor to
the place of the latest returned row,
@@ -3174,7 +3190,7 @@ row_search_for_mysql(
prebuilt->n_fetch_cached = 0;
prebuilt->fetch_cache_first = 0;
- } else if (prebuilt->n_fetch_cached > 0) {
+ } else if (UNIV_LIKELY(prebuilt->n_fetch_cached > 0)) {
row_sel_pop_cached_row_for_mysql(buf, prebuilt);
prebuilt->n_rows_fetched++;
@@ -3234,7 +3250,8 @@ row_search_for_mysql(
1 column. Return immediately if this is not a HANDLER
command. */
- if (direction != 0 && !prebuilt->used_in_HANDLER) {
+ if (UNIV_UNLIKELY(direction != 0 &&
+ !prebuilt->used_in_HANDLER)) {
err = DB_RECORD_NOT_FOUND;
goto func_exit;
@@ -3252,9 +3269,9 @@ row_search_for_mysql(
cannot use the adaptive hash index in a search in the case the row
may be long and there may be externally stored fields */
- if (unique_search
+ if (UNIV_UNLIKELY(direction == 0)
+ && unique_search
&& index->type & DICT_CLUSTERED
- && direction == 0
&& !prebuilt->templ_contains_blob
&& !prebuilt->used_in_HANDLER
&& (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
@@ -3286,9 +3303,9 @@ row_search_for_mysql(
trx->has_search_latch = TRUE;
}
#endif
- shortcut = row_sel_try_search_shortcut_for_mysql(&rec,
- prebuilt, &offsets, &heap, &mtr);
- if (shortcut == SEL_FOUND) {
+ switch (row_sel_try_search_shortcut_for_mysql(&rec,
+ prebuilt, &offsets, &heap, &mtr)) {
+ case SEL_FOUND:
#ifdef UNIV_SEARCH_DEBUG
ut_a(0 == cmp_dtuple_rec(search_tuple,
rec, offsets));
@@ -3322,9 +3339,8 @@ row_search_for_mysql(
position */
err = DB_SUCCESS;
goto func_exit;
-
- } else if (shortcut == SEL_EXHAUSTED) {
+ case SEL_EXHAUSTED:
mtr_commit(&mtr);
/* ut_print_name(stderr, index->name);
@@ -3367,6 +3383,7 @@ shortcut_fails_too_big_rec:
/* Scan the MySQL query string; check if SELECT is the first
word there */
+ ibool success;
dict_accept(*trx->mysql_query_str, "SELECT", &success);
@@ -3382,7 +3399,7 @@ shortcut_fails_too_big_rec:
naturally moves upward (in fetch next) in alphabetical order,
otherwise downward */
- if (direction == 0) {
+ if (UNIV_UNLIKELY(direction == 0)) {
if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G) {
moves_up = TRUE;
}
@@ -3396,10 +3413,10 @@ shortcut_fails_too_big_rec:
clust_index = dict_table_get_first_index(index->table);
- if (direction != 0) {
- moved = sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur,
- moves_up, &mtr);
- if (!moved) {
+ if (UNIV_LIKELY(direction != 0)) {
+ if (!sel_restore_position_for_mysql(&same_user_rec,
+ BTR_SEARCH_LEAF,
+ pcur, moves_up, &mtr)) {
goto next_rec;
}
@@ -3440,11 +3457,13 @@ shortcut_fails_too_big_rec:
trx_assign_read_view(trx);
prebuilt->sql_stat_start = FALSE;
} else {
+ ulint lock_mode;
if (prebuilt->select_lock_type == LOCK_S) {
- err = lock_table(0, index->table, LOCK_IS, thr);
+ lock_mode = LOCK_IS;
} else {
- err = lock_table(0, index->table, LOCK_IX, thr);
+ lock_mode = LOCK_IX;
}
+ err = lock_table(0, index->table, lock_mode, thr);
if (err != DB_SUCCESS) {
@@ -3458,8 +3477,8 @@ rec_loop:
/* PHASE 4: Look for matching records in a loop */
rec = btr_pcur_get_rec(pcur);
- comp = index->table->comp;
- ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
+#ifdef UNIV_SEARCH_DEBUG
/*
fputs("Using ", stderr);
dict_index_name_print(stderr, index);
@@ -3467,7 +3486,9 @@ rec_loop:
buf_frame_get_page_no(buf_frame_align(rec)));
rec_print(rec);
*/
- if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
+#endif /* UNIV_SEARCH_DEBUG */
+
+ if (page_rec_is_infimum(rec)) {
/* The infimum record on a page cannot be in the result set,
and neither can a record lock be placed on it: we skip such
@@ -3476,10 +3497,11 @@ rec_loop:
goto next_rec;
}
- if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
+ if (page_rec_is_supremum(rec)) {
- if (prebuilt->select_lock_type != LOCK_NONE
- && set_also_gap_locks) {
+ if (set_also_gap_locks
+ && !srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record */
@@ -3487,18 +3509,16 @@ rec_loop:
we do not lock gaps. Supremum record is really
a gap and therefore we do not set locks there. */
- if (!srv_locks_unsafe_for_binlog) {
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- err = sel_set_rec_lock(rec, index, offsets,
- prebuilt->select_lock_type,
- LOCK_ORDINARY, thr);
- if (err != DB_SUCCESS) {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ err = sel_set_rec_lock(rec, index, offsets,
+ prebuilt->select_lock_type,
+ LOCK_ORDINARY, thr);
- goto lock_wait_or_error;
- }
- }
+ if (err != DB_SUCCESS) {
+ goto lock_wait_or_error;
+ }
}
/* A page supremum record cannot be in the result set: skip
it now that we have placed a possible lock on it */
@@ -3510,12 +3530,19 @@ rec_loop:
/* Do sanity checks in case our cursor has bumped into page
corruption */
- next_offs = rec_get_next_offs(rec, comp);
-
- if (next_offs >= UNIV_PAGE_SIZE
- || next_offs <
- (ulint) (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM)) {
-
+ if (page_rec_is_comp(rec)) {
+ next_offs = rec_get_next_offs(rec, TRUE);
+ if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
+ goto wrong_offs;
+ }
+ } else {
+ next_offs = rec_get_next_offs(rec, FALSE);
+ if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
+ goto wrong_offs;
+ }
+ }
+ if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
+ wrong_offs:
if (srv_force_recovery == 0 || moves_up == FALSE) {
ut_print_timestamp(stderr);
buf_page_print(buf_frame_align(rec));
@@ -3528,7 +3555,7 @@ rec_loop:
fprintf(stderr,
"InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n"
"InnoDB: ",
- (ulong) (rec - buf_frame_align(rec)),
+ (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
dict_index_name_print(stderr, trx, index);
@@ -3546,7 +3573,7 @@ rec_loop:
fprintf(stderr,
"InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n"
"InnoDB: ",
- (ulong) (rec - buf_frame_align(rec)),
+ (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
dict_index_name_print(stderr, trx, index);
@@ -3561,13 +3588,13 @@ rec_loop:
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
- if (srv_force_recovery > 0) {
+ if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
if (!rec_validate(rec, offsets)
|| !btr_index_rec_validate(rec, index, FALSE)) {
fprintf(stderr,
"InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n"
"InnoDB: ",
- (ulong) (rec - buf_frame_align(rec)),
+ (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
dict_index_name_print(stderr, trx, index);
@@ -3593,25 +3620,22 @@ rec_loop:
if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
- if (prebuilt->select_lock_type != LOCK_NONE
- && set_also_gap_locks) {
+ if (set_also_gap_locks
+ && !srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
- if (srv_locks_unsafe_for_binlog == FALSE) {
-
- err = sel_set_rec_lock(rec, index,
- offsets,
+ err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
- if (err != DB_SUCCESS) {
- goto lock_wait_or_error;
- }
- }
+ if (err != DB_SUCCESS) {
+ goto lock_wait_or_error;
+ }
}
btr_pcur_store_position(pcur, &mtr);
@@ -3627,25 +3651,22 @@ rec_loop:
if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
- if (prebuilt->select_lock_type != LOCK_NONE
- && set_also_gap_locks) {
+ if (set_also_gap_locks
+ && !srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
- if (srv_locks_unsafe_for_binlog == FALSE) {
-
- err = sel_set_rec_lock(rec, index,
- offsets,
+ err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
- if (err != DB_SUCCESS) {
- goto lock_wait_or_error;
- }
- }
+ if (err != DB_SUCCESS) {
+ goto lock_wait_or_error;
+ }
}
btr_pcur_store_position(pcur, &mtr);
@@ -3657,33 +3678,30 @@ rec_loop:
goto normal_return;
}
}
-
+
/* We are ready to look at a possible new index entry in the result
set: the cursor is now placed on a user record */
- cons_read_requires_clust_rec = FALSE;
-
if (prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record; note that delete
marked records are a special case in a unique search. If there
is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */
+ /* If innodb_locks_unsafe_for_binlog option is used,
+ we lock only the record, i.e., next-key locking is
+ not used. */
+
ulint lock_type;
if (!set_also_gap_locks
- || (unique_search && !rec_get_deleted_flag(rec, comp))) {
- lock_type = LOCK_REC_NOT_GAP;
- } else {
- /* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e., next-key locking is
- not used. */
+ || srv_locks_unsafe_for_binlog
+ || (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag(
+ rec, page_rec_is_comp(rec))))) {
- if (srv_locks_unsafe_for_binlog) {
- lock_type = LOCK_REC_NOT_GAP;
- } else {
- lock_type = LOCK_ORDINARY;
- }
+ goto no_gap_lock;
+ } else {
+ lock_type = LOCK_ORDINARY;
}
/* If we are doing a 'greater or equal than a primary key
@@ -3703,7 +3721,7 @@ rec_loop:
&& dtuple_get_n_fields_cmp(search_tuple)
== dict_index_get_n_unique(index)
&& 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) {
-
+no_gap_lock:
lock_type = LOCK_REC_NOT_GAP;
}
@@ -3731,7 +3749,7 @@ rec_loop:
high force recovery level set, we try to avoid crashes
by skipping this lookup */
- if (srv_force_recovery < 5
+ if (UNIV_LIKELY(srv_force_recovery < 5)
&& !lock_clust_rec_cons_read_sees(rec, index,
offsets, trx->read_view)) {
@@ -3762,17 +3780,31 @@ rec_loop:
have to look also into the clustered index: this
is necessary, because we can only get the undo
information via the clustered index record. */
-
- cons_read_requires_clust_rec = TRUE;
+
+ /* Get the clustered index record if needed */
+ index_rec = rec;
+ ut_ad(index != clust_index);
+
+ goto requires_clust_rec;
}
}
- if (rec_get_deleted_flag(rec, comp)
- && !cons_read_requires_clust_rec) {
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, page_rec_is_comp(rec)))) {
/* The record is delete-marked: we can skip it if this is
not a consistent read which might see an earlier version
of a non-clustered index record */
+
+ if (srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
+
+ /* No need to keep a lock on a delete-marked record
+ if we do not want to use next-key locking. */
+
+ row_unlock_for_mysql(prebuilt, TRUE);
+
+ trx_reset_new_rec_lock_info(trx);
+ }
goto next_rec;
}
@@ -3782,14 +3814,15 @@ rec_loop:
index_rec = rec;
- /* Before and after the following "if" block, "offsets" will be
- related to "rec", which may be in "index", a secondary index or
- the clustered index ("clust_index"). However, after this "if" block,
- "rec" may be pointing to "clust_rec" of "clust_index". */
- ut_ad(rec_offs_validate(rec, index, offsets));
+ if (index != clust_index && prebuilt->need_to_access_clustered) {
- if (index != clust_index && (cons_read_requires_clust_rec
- || prebuilt->need_to_access_clustered)) {
+requires_clust_rec:
+ /* Before and after this "if" block, "offsets" will be
+ related to "rec", which may be in a secondary index "index" or
+ the clustered index ("clust_index"). However, after this
+ "if" block, "rec" may be pointing to
+ "clust_rec" of "clust_index". */
+ ut_ad(rec_offs_validate(rec, index, offsets));
/* It was a non-clustered index and we must fetch also the
clustered index record */
@@ -3811,10 +3844,23 @@ rec_loop:
goto next_rec;
}
- if (rec_get_deleted_flag(clust_rec, comp)) {
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec,
+ page_rec_is_comp(clust_rec)))) {
/* The record is delete marked: we can skip it */
+ if (srv_locks_unsafe_for_binlog
+ && prebuilt->select_lock_type != LOCK_NONE) {
+
+ /* No need to keep a lock on a delete-marked
+ record if we do not want to use next-key
+ locking. */
+
+ row_unlock_for_mysql(prebuilt, TRUE);
+
+ trx_reset_new_rec_lock_info(trx);
+ }
+
goto next_rec;
}
@@ -3832,7 +3878,8 @@ rec_loop:
rec == clust_rec ? clust_index : index,
offsets));
- if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
+ if ((match_mode == ROW_SEL_EXACT
+ || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
&& prebuilt->select_lock_type == LOCK_NONE
&& !prebuilt->templ_contains_blob
&& !prebuilt->clust_index_was_generated
@@ -3906,8 +3953,8 @@ got_row:
next_rec:
/*-------------------------------------------------------------*/
/* PHASE 5: Move the cursor to the next index record */
-
- if (mtr_has_extra_clust_latch) {
+
+ if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) {
/* We must commit mtr if we are moving to the next
non-clustered index record, because we could break the
latching order if we would access a different clustered
@@ -3919,34 +3966,39 @@ next_rec:
mtr_has_extra_clust_latch = FALSE;
mtr_start(&mtr);
- moved = sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur,
- moves_up, &mtr);
- if (moved) {
+ if (sel_restore_position_for_mysql(&same_user_rec,
+ BTR_SEARCH_LEAF,
+ pcur, moves_up, &mtr)) {
+#ifdef UNIV_SEARCH_DEBUG
cnt++;
+#endif /* UNIV_SEARCH_DEBUG */
goto rec_loop;
}
}
if (moves_up) {
- moved = btr_pcur_move_to_next(pcur, &mtr);
- } else {
- moved = btr_pcur_move_to_prev(pcur, &mtr);
- }
+ if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) {
+ not_moved:
+ btr_pcur_store_position(pcur, &mtr);
- if (!moved) {
- btr_pcur_store_position(pcur, &mtr);
+ if (match_mode != 0) {
+ err = DB_RECORD_NOT_FOUND;
+ } else {
+ err = DB_END_OF_INDEX;
+ }
- if (match_mode != 0) {
- err = DB_RECORD_NOT_FOUND;
- } else {
- err = DB_END_OF_INDEX;
+ goto normal_return;
+ }
+ } else {
+ if (UNIV_UNLIKELY(!btr_pcur_move_to_prev(pcur, &mtr))) {
+ goto not_moved;
}
-
- goto normal_return;
}
+#ifdef UNIV_SEARCH_DEBUG
cnt++;
+#endif /* UNIV_SEARCH_DEBUG */
goto rec_loop;
@@ -3964,23 +4016,49 @@ lock_wait_or_error:
que_thr_stop_for_mysql(thr);
- thr->lock_state= QUE_THR_LOCK_ROW;
- was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
- thr->lock_state= QUE_THR_LOCK_NOLOCK;
+ thr->lock_state = QUE_THR_LOCK_ROW;
+
+ if (row_mysql_handle_errors(&err, trx, thr, NULL)) {
+ /* It was a lock wait, and it ended */
- if (was_lock_wait) {
+ thr->lock_state = QUE_THR_LOCK_NOLOCK;
mtr_start(&mtr);
- sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur,
- moves_up, &mtr);
+ sel_restore_position_for_mysql(&same_user_rec,
+ BTR_SEARCH_LEAF, pcur,
+ moves_up, &mtr);
+ if (srv_locks_unsafe_for_binlog && !same_user_rec) {
+ /* Since we were not able to restore the cursor
+ on the same user record, we cannot use
+ row_unlock_for_mysql() to unlock any records, and
+ we must thus reset the new rec lock info. Since
+ in lock0lock.c we have blocked the inheriting of gap
+ X-locks, we actually do not have any new record locks
+ set in this case.
+
+ Note that if we were able to restore on the 'same'
+ user record, it is still possible that we were actually
+ waiting on a delete-marked record, and meanwhile
+ it was removed by purge and inserted again by some
+ other user. But that is no problem, because in
+ rec_loop we will again try to set a lock, and
+ new_rec_lock_info in trx will be right at the end. */
+
+ trx_reset_new_rec_lock_info(trx);
+ }
+
mode = pcur->search_mode;
goto rec_loop;
}
+ thr->lock_state = QUE_THR_LOCK_NOLOCK;
+
+#ifdef UNIV_SEARCH_DEBUG
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
+#endif /* UNIV_SEARCH_DEBUG */
goto func_exit;
normal_return:
@@ -3995,16 +4073,18 @@ normal_return:
err = DB_SUCCESS;
}
+#ifdef UNIV_SEARCH_DEBUG
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
+#endif /* UNIV_SEARCH_DEBUG */
if (err == DB_SUCCESS) {
srv_n_rows_read++;
}
func_exit:
trx->op_info = "";
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index 1cade0f304f..0225a9faec5 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -52,19 +52,16 @@ row_undo_mod_undo_also_prev_vers(
/* out: TRUE if also previous modify or
insert of this row should be undone */
undo_node_t* node, /* in: row undo node */
- que_thr_t* thr, /* in: query thread */
dulint* undo_no)/* out: the undo number */
{
trx_undo_rec_t* undo_rec;
- ibool ret;
trx_t* trx;
- UT_NOT_USED(thr);
-
trx = node->trx;
if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) {
+ *undo_no = ut_dulint_zero;
return(FALSE);
}
@@ -72,13 +69,7 @@ row_undo_mod_undo_also_prev_vers(
*undo_no = trx_undo_rec_get_undo_no(undo_rec);
- if (ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0) {
- ret = TRUE;
- } else {
- ret = FALSE;
- }
-
- return(ret);
+ return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0);
}
/***************************************************************
@@ -214,7 +205,7 @@ row_undo_mod_clust(
/* Check if also the previous version of the clustered index record
should be undone in this same rollback operation */
- more_vers = row_undo_mod_undo_also_prev_vers(node, thr, &new_undo_no);
+ more_vers = row_undo_mod_undo_also_prev_vers(node, &new_undo_no);
pcur = &(node->pcur);
diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c
index abe73cbe705..435c0279dbb 100644
--- a/innobase/row/row0undo.c
+++ b/innobase/row/row0undo.c
@@ -190,7 +190,7 @@ row_undo_search_clust_to_pcur(
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(ret);
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 3305724a89b..514fb6bd577 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -815,9 +815,10 @@ row_upd_build_difference_binary(
goto skip_compare;
}
- extern_bit = rec_offs_nth_extern(offsets, i);
+ extern_bit = upd_ext_vec_contains(ext_vec, n_ext_vec, i);
- if (extern_bit != upd_ext_vec_contains(ext_vec, n_ext_vec, i)
+ if (UNIV_UNLIKELY(extern_bit ==
+ (ibool)!rec_offs_nth_extern(offsets, i))
|| !dfield_data_is_binary_equal(dfield, len, data)) {
upd_field = upd_get_nth_field(update, n_diff);
@@ -826,12 +827,8 @@ row_upd_build_difference_binary(
upd_field_set_field_no(upd_field, i, index, trx);
- if (upd_ext_vec_contains(ext_vec, n_ext_vec, i)) {
- upd_field->extern_storage = TRUE;
- } else {
- upd_field->extern_storage = FALSE;
- }
-
+ upd_field->extern_storage = extern_bit;
+
n_diff++;
}
skip_compare:
@@ -1224,7 +1221,7 @@ row_upd_store_row(
node->n_ext_vec = btr_push_update_extern_fields(node->ext_vec,
offsets, update);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -1270,7 +1267,7 @@ row_upd_sec_index_entry(
rec = btr_cur_get_rec(btr_cur);
- if (!found) {
+ if (UNIV_UNLIKELY(!found)) {
fputs("InnoDB: error in sec index entry update in\n"
"InnoDB: ", stderr);
dict_index_name_print(stderr, trx, index);
@@ -1423,7 +1420,7 @@ row_upd_clust_rec_by_insert(
index, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -1549,7 +1546,7 @@ row_upd_clust_rec(
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap),
big_rec, mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
mtr_commit(mtr);
@@ -1719,7 +1716,7 @@ row_upd_clust_step(
node->index = dict_table_get_next_index(index);
}
exit_func:
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
@@ -1736,7 +1733,7 @@ row_upd_clust_step(
row_upd_eval_new_vals(node->update);
}
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -2016,7 +2013,7 @@ row_upd_in_place_in_select(
btr_pcur_get_rec(pcur), btr_cur->index, offsets_,
ULINT_UNDEFINED, &heap),
UT_LIST_GET_FIRST(node->columns));
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
row_upd_eval_new_vals(node->update);
diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c
index 36f6c27636d..8e747423047 100644
--- a/innobase/row/row0vers.c
+++ b/innobase/row/row0vers.c
@@ -57,11 +57,11 @@ row_vers_impl_x_locked_off_kernel(
dtuple_t* entry = NULL; /* assignment to eliminate compiler
warning */
trx_t* trx;
- ibool vers_del;
- ibool rec_del;
+ ulint vers_del;
+ ulint rec_del;
ulint err;
mtr_t mtr;
- ibool comp;
+ ulint comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -121,10 +121,10 @@ row_vers_impl_x_locked_off_kernel(
goto exit_func;
}
- comp = index->table->comp;
+ comp = page_rec_is_comp(rec);
ut_ad(index->table == clust_index->table);
- ut_ad(comp == page_is_comp(buf_frame_align(rec)));
- ut_ad(comp == page_is_comp(buf_frame_align(clust_rec)));
+ ut_ad(!!comp == index->table->comp);
+ ut_ad(!comp == !page_rec_is_comp(clust_rec));
/* We look up if some earlier version, which was modified by the trx_id
transaction, of the clustered index record would require rec to be in
@@ -310,7 +310,7 @@ row_vers_old_has_index_entry(
dtuple_t* row;
dtuple_t* entry;
ulint err;
- ibool comp;
+ ulint comp;
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
|| mtr_memo_contains(mtr, buf_block_align(rec),
@@ -322,8 +322,8 @@ row_vers_old_has_index_entry(
clust_index = dict_table_get_first_index(index->table);
- comp = index->table->comp;
- ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ comp = page_rec_is_comp(rec);
+ ut_ad(!index->table->comp == !comp);
heap = mem_heap_create(1024);
clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index f901425a5f9..837c5be2bb6 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -260,7 +260,7 @@ semaphore contention and convoy problems can occur withput this restriction.
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 = 8;
+ulong srv_thread_concurrency = SRV_CONCURRENCY_THRESHOLD;
os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data
structures */
@@ -983,12 +983,6 @@ srv_conc_enter_innodb(
srv_conc_slot_t* slot = NULL;
ulint i;
- if (srv_thread_concurrency >= 500) {
- /* Disable the concurrency check */
-
- return;
- }
-
/* If trx has 'free tickets' to enter the engine left, then use one
such ticket */
@@ -1134,7 +1128,7 @@ srv_conc_force_enter_innodb(
trx_t* trx) /* in: transaction object associated with the
thread */
{
- if (srv_thread_concurrency >= 500) {
+ if (srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD) {
return;
}
@@ -1160,7 +1154,7 @@ srv_conc_force_exit_innodb(
{
srv_conc_slot_t* slot = NULL;
- if (srv_thread_concurrency >= 500) {
+ if (srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD) {
return;
}
@@ -1212,11 +1206,6 @@ srv_conc_exit_innodb(
trx_t* trx) /* in: transaction object associated with the
thread */
{
- if (srv_thread_concurrency >= 500) {
-
- return;
- }
-
if (trx->n_tickets_to_enter_innodb > 0) {
/* We will pretend the thread is still inside InnoDB though it
now leaves the InnoDB engine. In this way we save
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 541b73b831d..7798e0c8e32 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1040,7 +1040,9 @@ innobase_start_or_create_for_mysql(void)
srv_start_has_been_called = TRUE;
+#ifdef UNIV_DEBUG
log_do_write = TRUE;
+#endif /* UNIV_DEBUG */
/* yydebug = TRUE; */
srv_is_being_started = TRUE;
@@ -1554,8 +1556,9 @@ NetWare. */
os_thread_create(&srv_master_thread, NULL, thread_ids + 1 +
SRV_MAX_N_IO_THREADS);
+#ifdef UNIV_DEBUG
/* buf_debug_prints = TRUE; */
-
+#endif /* UNIV_DEBUG */
sum_of_data_file_sizes = 0;
for (i = 0; i < srv_n_data_files; i++) {
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index e604912e996..f0f0e9a3a2e 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -1136,8 +1136,12 @@ sync_thread_add_level(
} else if (level == SYNC_DICT_HEADER) {
ut_a(sync_thread_levels_g(array, SYNC_DICT_HEADER));
} else if (level == SYNC_DICT) {
+#ifdef UNIV_DEBUG
ut_a(buf_debug_prints
|| sync_thread_levels_g(array, SYNC_DICT));
+#else /* UNIV_DEBUG */
+ ut_a(sync_thread_levels_g(array, SYNC_DICT));
+#endif /* UNIV_DEBUG */
} else {
ut_error;
}
diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c
index fcb7582ce73..3b7171e6038 100644
--- a/innobase/trx/trx0rec.c
+++ b/innobase/trx/trx0rec.c
@@ -941,13 +941,11 @@ trx_undo_erase_page_end(
mtr_t* mtr) /* in: mtr */
{
ulint first_free;
- ulint i;
-
+
first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_FREE);
- for (i = first_free; i < UNIV_PAGE_SIZE - FIL_PAGE_DATA_END; i++) {
- undo_page[i] = 0xFF;
- }
+ memset(undo_page + first_free, 0xff,
+ (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free);
mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr);
}
@@ -1134,7 +1132,7 @@ trx_undo_report_row_operation(
mutex_exit(&(trx->undo_mutex));
mtr_commit(&mtr);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(DB_OUT_OF_FILE_SPACE);
@@ -1153,7 +1151,7 @@ trx_undo_report_row_operation(
*roll_ptr = trx_undo_build_roll_ptr(is_insert, rseg->id, page_no,
offset);
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(DB_SUCCESS);
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index 69f7a99187f..fdfb7428129 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -1237,10 +1237,12 @@ trx_finish_rollback_off_kernel(
return;
}
+#ifdef UNIV_DEBUG
if (lock_print_waits) {
fprintf(stderr, "Trx %lu rollback finished\n",
(ulong) ut_dulint_get_low(trx->id));
}
+#endif /* UNIV_DEBUG */
trx_commit_off_kernel(trx);
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index c6d1f953772..10fbf3468c0 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -158,8 +158,6 @@ trx_create(
trx->n_tickets_to_enter_innodb = 0;
trx->auto_inc_lock = NULL;
- trx->n_lock_table_exp = 0;
- trx->n_lock_table_transactional = 0;
trx->read_view_heap = mem_heap_create(256);
trx->read_view = NULL;
@@ -168,6 +166,8 @@ trx_create(
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
+ trx_reset_new_rec_lock_info(trx);
+
return(trx);
}
@@ -309,8 +309,6 @@ trx_free(
ut_a(!trx->has_search_latch);
ut_a(!trx->auto_inc_lock);
- ut_a(!trx->n_lock_table_exp);
- ut_a(!trx->n_lock_table_transactional);
ut_a(trx->dict_operation_lock_mode == 0);
@@ -1711,12 +1709,6 @@ trx_print(
(ulong) trx->mysql_n_tables_locked);
}
- if (trx->n_lock_table_transactional > 0 || trx->n_lock_table_exp > 0) {
-fprintf(f, "mysql explicit table locks %lu, transactional table locks %lu\n",
- (ulong) trx->n_lock_table_exp,
- (ulong) trx->n_lock_table_transactional);
- }
-
newline = TRUE;
switch (trx->que_state) {
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index bb314dd35e9..7441dd3f152 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -556,19 +556,19 @@ void
trx_undo_write_xid(
/*===============*/
trx_ulogf_t* log_hdr,/* in: undo log header */
- XID* xid, /* in: X/Open XA Transaction Identification */
+ const XID* xid, /* in: X/Open XA Transaction Identification */
mtr_t* mtr) /* in: mtr */
{
- mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT, xid->formatID,
- MLOG_4BYTES, mtr);
+ mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
+ (ulint)xid->formatID, MLOG_4BYTES, mtr);
- mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN, xid->gtrid_length,
- MLOG_4BYTES, mtr);
+ mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
+ (ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
- mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN, xid->bqual_length,
- MLOG_4BYTES, mtr);
+ mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
+ (ulint)xid->bqual_length, MLOG_4BYTES, mtr);
- mlog_write_string(log_hdr + TRX_UNDO_XA_XID, xid->data,
+ mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
XIDDATASIZE, mtr);
}
@@ -581,18 +581,14 @@ trx_undo_read_xid(
trx_ulogf_t* log_hdr,/* in: undo log header */
XID* xid) /* out: X/Open XA Transaction Identification */
{
- ulint i;
-
- xid->formatID = mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
+ xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
- xid->gtrid_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
-
- xid->bqual_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
+ xid->gtrid_length =
+ (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
+ xid->bqual_length =
+ (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
- for (i = 0; i < XIDDATASIZE; i++) {
- xid->data[i] = (char)mach_read_from_1(log_hdr +
- TRX_UNDO_XA_XID + i);
- }
+ memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
}
/*******************************************************************
diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c
index 0f6a27d35d9..e810d8dead7 100644
--- a/innobase/ut/ut0dbg.c
+++ b/innobase/ut/ut0dbg.c
@@ -8,8 +8,11 @@ Created 1/30/1994 Heikki Tuuri
#include "univ.i"
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#else
/* This is used to eliminate compiler warnings */
ulint ut_dbg_zero = 0;
+#endif
/* If this is set to TRUE all threads will stop into the next assertion
and assert */
@@ -19,21 +22,69 @@ ibool panic_shutdown = FALSE; /* This is set to TRUE when on NetWare there
happens an InnoDB assertion failure or other
fatal error condition that requires an
immediate shutdown. */
-#endif
+#else /* __NETWARE__ */
/* Null pointer used to generate memory trap */
ulint* ut_dbg_null_ptr = NULL;
+#endif /* __NETWARE__ */
+
+/*****************************************************************
+Report a failed assertion. */
-const char* ut_dbg_msg_assert_fail =
-"InnoDB: Assertion failure in thread %lu in file %s line %lu\n";
-const char* ut_dbg_msg_trap =
+void
+ut_dbg_assertion_failed(
+/*====================*/
+ const char* expr, /* in: the failed assertion (optional) */
+ const char* file, /* in: source file containing the assertion */
+ ulint line) /* in: line number of the assertion */
+{
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ "InnoDB: Assertion failure in thread %lu"
+ " in file %s line %lu\n",
+ os_thread_pf(os_thread_get_curr_id()), file, line);
+ if (expr) {
+ fprintf(stderr,
+ "InnoDB: Failing assertion: %s\n", expr);
+ }
+
+ fputs(
"InnoDB: We intentionally generate a memory trap.\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n"
"InnoDB: If you get repeated assertion failures or crashes, even\n"
"InnoDB: immediately after the mysqld startup, there may be\n"
"InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
-"InnoDB: about forcing recovery.\n";
+"InnoDB: about forcing recovery.\n", stderr);
+ ut_dbg_stop_threads = TRUE;
+}
+
+#ifdef __NETWARE__
+/*****************************************************************
+Shut down MySQL/InnoDB after assertion failure. */
+
+void
+ut_dbg_panic(void)
+/*==============*/
+{
+ if (!panic_shutdown) {
+ panic_shutdown = TRUE;
+ innobase_shutdown_for_mysql();
+ }
+ exit(1);
+}
+#else /* __NETWARE__ */
+/*****************************************************************
+Stop a thread after assertion failure. */
-const char* ut_dbg_msg_stop =
-"InnoDB: Thread %lu stopped in file %s line %lu\n";
+void
+ut_dbg_stop_thread(
+/*===============*/
+ const char* file,
+ ulint line)
+{
+ fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n",
+ os_thread_pf(os_thread_get_curr_id()), file, line);
+ os_thread_sleep(1000000000);
+}
+#endif /* __NETWARE__ */
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 0670a0befa8..4bd9eddafb0 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -23,8 +23,8 @@
target = libmysqlclient.la
target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
LIBS = @CLIENT_LIBS@
-INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \
- -I$(top_builddir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(openssl_includes) @ZLIB_INCLUDES@
include $(srcdir)/Makefile.shared
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 753657951ee..f9ddf7fa665 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1495,40 +1495,22 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql)
return mysql->charset->csname;
}
-
-int STDCALL mysql_set_character_set(MYSQL *mysql, char *cs_name)
+void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo)
{
- struct charset_info_st *cs;
- const char *save_csdir= charsets_dir;
+ csinfo->number = mysql->charset->number;
+ csinfo->state = mysql->charset->state;
+ csinfo->csname = mysql->charset->csname;
+ csinfo->name = mysql->charset->name;
+ csinfo->comment = mysql->charset->comment;
+ csinfo->mbminlen = mysql->charset->mbminlen;
+ csinfo->mbmaxlen = mysql->charset->mbmaxlen;
if (mysql->options.charset_dir)
- charsets_dir= mysql->options.charset_dir;
-
- if ((cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
- {
- char buff[MY_CS_NAME_SIZE + 10];
- charsets_dir= save_csdir;
- sprintf(buff, "SET NAMES %s", cs_name);
- if (!mysql_query(mysql, buff))
- {
- mysql->charset= cs;
- }
- }
+ csinfo->dir = mysql->options.charset_dir;
else
- {
- char cs_dir_name[FN_REFLEN];
- get_charsets_dir(cs_dir_name);
- mysql->net.last_errno= CR_CANT_READ_CHARSET;
- strmov(mysql->net.sqlstate, unknown_sqlstate);
- my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
- ER(mysql->net.last_errno), cs_name, cs_dir_name);
-
- }
- charsets_dir= save_csdir;
- return mysql->net.last_errno;
+ csinfo->dir = charsets_dir;
}
-
uint STDCALL mysql_thread_safe(void)
{
#ifdef THREAD
@@ -1616,7 +1598,14 @@ ulong STDCALL
mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
ulong length)
{
- return escape_string_for_mysql(mysql->charset, to, 0, from, length);
+ if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
+ {
+ return escape_quotes_for_mysql(mysql->charset, to, 0, from, length);
+ }
+ else
+ {
+ return escape_string_for_mysql(mysql->charset, to, 0, from, length);
+ }
}
@@ -1736,7 +1725,7 @@ myodbc_remove_escape(MYSQL *mysql,char *name)
/******************* Declarations ***********************************/
-/* Default number of rows fetched per one COM_FETCH command. */
+/* Default number of rows fetched per one COM_STMT_FETCH command. */
#define DEFAULT_PREFETCH_ROWS (ulong) 1
@@ -1752,6 +1741,7 @@ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row);
static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row);
static int stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row);
static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
+static int stmt_read_row_no_result_set(MYSQL_STMT *stmt, unsigned char **row);
/*
This function is used in mysql_stmt_store_result if
@@ -1847,6 +1837,16 @@ static void net_clear_error(NET *net)
}
}
+static void stmt_clear_error(MYSQL_STMT *stmt)
+{
+ if (stmt->last_errno)
+ {
+ stmt->last_errno= 0;
+ stmt->last_error[0]= '\0';
+ strmov(stmt->sqlstate, not_error_sqlstate);
+ }
+}
+
/*
Set statement error code, sqlstate, and error message
from given errcode and sqlstate.
@@ -1887,7 +1887,7 @@ void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode,
}
/*
- Read and unpack server reply to COM_PREPARE command (sent from
+ Read and unpack server reply to COM_STMT_PREPARE command (sent from
mysql_stmt_prepare).
SYNOPSIS
@@ -2004,7 +2004,7 @@ mysql_stmt_init(MYSQL *mysql)
stmt->list.data= stmt;
stmt->state= MYSQL_STMT_INIT_DONE;
stmt->mysql= mysql;
- stmt->read_row_func= stmt_read_row_no_data;
+ stmt->read_row_func= stmt_read_row_no_result_set;
stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS;
/* The rest of statement members was bzeroed inside malloc */
@@ -2082,7 +2082,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
mysql_use_result it won't be freed in mysql_stmt_free_result and
we should get 'Commands out of sync' here.
*/
- if (simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
+ if (simple_command(mysql, COM_STMT_CLOSE, buff, 4, 1))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
mysql->net.sqlstate);
@@ -2091,7 +2091,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
stmt->state= MYSQL_STMT_INIT_DONE;
}
- if (simple_command(mysql, COM_PREPARE, query, length, 1))
+ if (simple_command(mysql, COM_STMT_PREPARE, query, length, 1))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
mysql->net.sqlstate);
@@ -2175,7 +2175,7 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
/*
Update result set columns metadata if it was sent again in
- reply to COM_EXECUTE.
+ reply to COM_STMT_EXECUTE.
*/
static void update_stmt_fields(MYSQL_STMT *stmt)
@@ -2490,7 +2490,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
/*
- Auxilary function to send COM_EXECUTE packet to server and read reply.
+ Auxilary function to send COM_STMT_EXECUTE packet to server and read reply.
Used from cli_stmt_execute, which is in turn used by mysql_stmt_execute.
*/
@@ -2507,7 +2507,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
buff[4]= (char) stmt->flags;
int4store(buff+5, 1); /* iteration count */
- if (cli_advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff),
+ if (cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
packet, length, 1) ||
(*mysql->methods->read_query_result)(mysql))
{
@@ -2720,13 +2720,12 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
/* Send row request to the server */
int4store(buff, stmt->stmt_id);
int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */
- if (cli_advanced_command(mysql, COM_FETCH, buff, sizeof(buff),
+ if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
NullS, 0, 1))
{
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
return 1;
}
- stmt->server_status= mysql->server_status;
if (cli_read_binary_rows(stmt))
return 1;
stmt->server_status= mysql->server_status;
@@ -2748,6 +2747,13 @@ static int
stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
unsigned char **row __attribute__((unused)))
{
+ return MYSQL_NO_DATA;
+}
+
+static int
+stmt_read_row_no_result_set(MYSQL_STMT *stmt __attribute__((unused)),
+ unsigned char **row __attribute__((unused)))
+{
set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate);
return 1;
}
@@ -2910,7 +2916,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
- if data dictionary changed between prepare and execute, for
example a table used in the query was altered.
Note, that now (4.1.3) we always send metadata in reply to
- COM_EXECUTE (even if it is not necessary), so either this or
+ COM_STMT_EXECUTE (even if it is not necessary), so either this or
previous branch always works.
TODO: send metadata only when it's really necessary and add a warning
'Metadata changed' when it's sent twice.
@@ -3380,8 +3386,9 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
Note that we don't get any ok packet from the server in this case
This is intentional to save bandwidth.
*/
- if ((*mysql->methods->advanced_command)(mysql, COM_LONG_DATA, buff,
- sizeof(buff), data, length, 1))
+ if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA,
+ buff, sizeof(buff), data,
+ length, 1))
{
set_stmt_errmsg(stmt, mysql->net.last_error,
mysql->net.last_errno, mysql->net.sqlstate);
@@ -4568,7 +4575,8 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
((rc= stmt_fetch_row(stmt, row)) && rc != MYSQL_DATA_TRUNCATED))
{
stmt->state= MYSQL_STMT_PREPARE_DONE; /* XXX: this is buggy */
- stmt->read_row_func= stmt_read_row_no_data;
+ stmt->read_row_func= (rc == MYSQL_NO_DATA) ?
+ stmt_read_row_no_data : stmt_read_row_no_result_set;
}
else
{
@@ -4885,13 +4893,12 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
{
MYSQL *mysql= stmt->mysql;
MYSQL_DATA *result= &stmt->result;
- my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor;
/*
Reset stored result set if so was requested or it's a part
of cursor fetch.
*/
- if (result->data && (has_cursor || (flags & RESET_STORE_RESULT)))
+ if (result->data && (flags & RESET_STORE_RESULT))
{
/* Result buffered */
free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
@@ -4906,7 +4913,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
for (; param < param_end; param++)
param->long_data_used= 0;
}
- stmt->read_row_func= stmt_read_row_no_data;
+ stmt->read_row_func= stmt_read_row_no_result_set;
if (mysql)
{
if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
@@ -4922,7 +4929,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
mysql->status= MYSQL_STATUS_READY;
}
}
- if (has_cursor || (flags & RESET_SERVER_SIDE))
+ if (flags & RESET_SERVER_SIDE)
{
/*
Reset the server side statement and close the server side
@@ -4930,7 +4937,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
*/
char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
int4store(buff, stmt->stmt_id);
- if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff,
+ if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff,
sizeof(buff), 0, 0, 0))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
@@ -4938,6 +4945,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
stmt->state= MYSQL_STMT_INIT_DONE;
return 1;
}
+ stmt_clear_error(stmt);
}
}
stmt->state= MYSQL_STMT_PREPARE_DONE;
@@ -5004,7 +5012,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
mysql->status= MYSQL_STATUS_READY;
}
int4store(buff, stmt->stmt_id);
- if ((rc= simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1)))
+ if ((rc= simple_command(mysql, COM_STMT_CLOSE, buff, 4, 1)))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
mysql->net.sqlstate);
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
index 2da88c271ba..0688ea5732b 100644
--- a/libmysql/libmysql.def
+++ b/libmysql/libmysql.def
@@ -149,5 +149,6 @@ EXPORTS
mysql_server_init
mysql_server_end
mysql_set_character_set
+ mysql_get_character_set_info
get_defaults_files
modify_defaults_file
diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am
index 1a69dbb804a..65255066d45 100644
--- a/libmysql_r/Makefile.am
+++ b/libmysql_r/Makefile.am
@@ -24,8 +24,8 @@ target = libmysqlclient_r.la
target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@
LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@
-INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \
- -I$(top_builddir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(openssl_includes) @ZLIB_INCLUDES@
## automake barfs if you don't use $(srcdir) or $(top_srcdir) in include
include $(top_srcdir)/libmysql/Makefile.shared
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index ba63d213b88..9aef03f20d2 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -25,10 +25,10 @@ DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\""
-INCLUDES= @bdb_includes@ -I$(top_srcdir)/include \
+INCLUDES= @bdb_includes@ \
+ -I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_srcdir)/sql -I$(top_srcdir)/sql/examples \
-I$(top_srcdir)/regex \
- -I$(top_builddir)/include \
$(openssl_includes) @ZLIB_INCLUDES@
noinst_LIBRARIES = libmysqld_int.a
diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am
index 071a133ca2d..476f297fe0d 100644
--- a/libmysqld/examples/Makefile.am
+++ b/libmysqld/examples/Makefile.am
@@ -31,9 +31,9 @@ link_sources:
done;
DEFS = -DEMBEDDED_LIBRARY
-INCLUDES = -I$(top_srcdir)/include -I$(srcdir) \
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \
-I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \
- -I$(top_builddir)/include $(openssl_includes)
+ $(openssl_includes)
LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS)
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 74a1c8c7922..c3b239ac7b9 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -220,7 +220,7 @@ static int emb_stmt_execute(MYSQL_STMT *stmt)
THD *thd= (THD*)stmt->mysql->thd;
thd->client_param_count= stmt->param_count;
thd->client_params= stmt->params;
- if (emb_advanced_command(stmt->mysql, COM_EXECUTE,0,0,
+ if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
header, sizeof(header), 1) ||
emb_mysql_read_query_result(stmt->mysql))
{
@@ -773,7 +773,7 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
}
void
-send_eof(THD *thd, bool no_flush)
+send_eof(THD *thd)
{
}
diff --git a/myisam/Makefile.am b/myisam/Makefile.am
index c61647b25f7..e4327070997 100644
--- a/myisam/Makefile.am
+++ b/myisam/Makefile.am
@@ -17,7 +17,7 @@
EXTRA_DIST = mi_test_all.sh mi_test_all.res
pkgdata_DATA = mi_test_all mi_test_all.res
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
index 530f0d56c4c..35c41b7d2d6 100644
--- a/myisam/ft_boolean_search.c
+++ b/myisam/ft_boolean_search.c
@@ -410,7 +410,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
Hack: instead of init_queue, we'll use reinit queue to be able
to alloc queue with alloc_root()
*/
- res=ftb->queue.max_elements=1+query_len/(min(ft_min_word_len,2)+1);
+ res=ftb->queue.max_elements=1+query_len/2;
if (!(ftb->queue.root=
(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*))))
goto err;
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
index 47332b02a72..33b344405ec 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -770,10 +770,13 @@ err:
uint mi_get_pointer_length(ulonglong file_length, uint def)
{
+ DBUG_ASSERT(def >= 2 && def <= 7);
if (file_length) /* If not default */
{
+#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
if (file_length >= (longlong) 1 << 56)
def=8;
+#endif
if (file_length >= (longlong) 1 << 48)
def=7;
if (file_length >= (longlong) 1 << 40)
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 456b87b7799..74b97a65609 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -78,7 +78,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
int lock_error,kfile,open_mode,save_errno,have_rtree=0;
uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
key_parts,unique_key_parts,fulltext_keys,uniques;
- char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN],
+ char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
data_name[FN_REFLEN];
char *disk_cache, *disk_pos, *end_pos;
MI_INFO info,*m_info,*old_info;
diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c
index 4b512dd89dd..c251e4dda4a 100644
--- a/myisam/mi_packrec.c
+++ b/myisam/mi_packrec.c
@@ -416,8 +416,19 @@ static uint find_longest_bitstream(uint16 *table, uint16 *end)
}
- /* Read record from datafile */
- /* Returns length of packed record, -1 if error */
+/*
+ Read record from datafile.
+
+ SYNOPSIS
+ _mi_read_pack_record()
+ info A pointer to MI_INFO.
+ filepos File offset of the record.
+ buf RETURN The buffer to receive the record.
+
+ RETURN
+ 0 on success
+ HA_ERR_WRONG_IN_RECORD or -1 on error
+*/
int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, byte *buf)
{
diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c
index f2d5f01be25..34f5f595f30 100644
--- a/myisam/mi_unique.c
+++ b/myisam/mi_unique.c
@@ -64,7 +64,12 @@ my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, byte *record,
}
-/* Calculate a hash for a row */
+/*
+ Calculate a hash for a row
+
+ TODO
+ Add support for bit fields
+*/
ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record)
{
@@ -126,9 +131,17 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record)
return crc;
}
- /*
- Returns 0 if both rows have equal unique value
- */
+
+/*
+ compare unique key for two rows
+
+ TODO
+ Add support for bit fields
+
+ RETURN
+ 0 if both rows have equal unique value
+ # Rows are different
+*/
int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
my_bool null_are_equal)
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index 74bb541b220..daf2bbdf85c 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -33,10 +33,10 @@
#include <my_getopt.h>
#include <assert.h>
-#if INT_MAX > 32767
-#define BITS_SAVED 32
+#if SIZEOF_LONG_LONG > 4
+#define BITS_SAVED 64
#else
-#define BITS_SAVED 16
+#define BITS_SAVED 32
#endif
#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
@@ -49,10 +49,10 @@
struct st_file_buffer {
File file;
- char *buffer,*pos,*end;
+ uchar *buffer,*pos,*end;
my_off_t pos_in_file;
int bits;
- uint current_byte;
+ ulonglong bitbucket;
};
struct st_huff_tree;
@@ -69,13 +69,17 @@ typedef struct st_huff_counts {
my_off_t end_space[8];
my_off_t pre_space[8];
my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
- TREE int_tree;
- byte *tree_buff;
- byte *tree_pos;
+ TREE int_tree; /* Tree for detecting distinct column values. */
+ byte *tree_buff; /* Column values, 'field_length' each. */
+ byte *tree_pos; /* Points to end of column values in 'tree_buff'. */
} HUFF_COUNTS;
typedef struct st_huff_element HUFF_ELEMENT;
+/*
+ WARNING: It is crucial for the optimizations in calc_packed_length()
+ that 'count' is the first element of 'HUFF_ELEMENT'.
+*/
struct st_huff_element {
my_off_t count;
union un_element {
@@ -98,7 +102,7 @@ typedef struct st_huff_tree {
my_off_t bytes_packed;
uint tree_pack_length;
uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
- ulong *code;
+ ulonglong *code;
uchar *code_len;
} HUFF_TREE;
@@ -146,7 +150,7 @@ static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
static void make_traverse_code_tree(HUFF_TREE *huff_tree,
HUFF_ELEMENT *element,uint size,
- ulong code);
+ ulonglong code);
static int write_header(PACK_MRG_INFO *isam_file, uint header_length,uint trees,
my_off_t tot_elements,my_off_t filelength);
static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
@@ -161,7 +165,7 @@ static char *make_old_name(char *new_name,char *old_name);
static void init_file_buffer(File file,pbool read_buffer);
static int flush_buffer(ulong neaded_length);
static void end_file_buffer(void);
-static void write_bits(ulong value,uint bits);
+static void write_bits(ulonglong value, uint bits);
static void flush_bits(void);
static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length,
ha_checksum crc);
@@ -170,13 +174,23 @@ static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,my_off_t new_length
static int mrg_close(PACK_MRG_INFO *mrg);
static int mrg_rrnd(PACK_MRG_INFO *info,byte *buf);
static void mrg_reset(PACK_MRG_INFO *mrg);
+#if !defined(DBUG_OFF)
+static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count);
+static int fakecmp(my_off_t **count1, my_off_t **count2);
+#endif
static int error_on_write=0,test_only=0,verbose=0,silent=0,
write_loop=0,force_pack=0, isamchk_neaded=0;
static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
static my_bool backup, opt_wait;
-static uint tree_buff_length=8196-MALLOC_OVERHEAD;
+/*
+ tree_buff_length is somewhat arbitrary. The bigger it is the better
+ the chance to win in terms of compression factor. On the other hand,
+ this table becomes part of the compressed file header. And its length
+ is coded with 16 bits in the header. Hence the limit is 2**16 - 1.
+*/
+static uint tree_buff_length= 65536 - MALLOC_OVERHEAD;
static char tmp_dir[FN_REFLEN]={0},*join_table;
static my_off_t intervall_length;
static ha_checksum glob_crc;
@@ -225,7 +239,8 @@ int main(int argc, char **argv)
}
if (ok && isamchk_neaded && !silent)
puts("Remember to run myisamchk -rq on compressed tables");
- VOID(fflush(stdout)); VOID(fflush(stderr));
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
free_defaults(default_argv);
my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
exit(error ? 2 : 0);
@@ -260,7 +275,7 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"test", 't', "Don't pack table, only test packing it.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"verbose", 'v', "Write info about progress and packing result.",
+ {"verbose", 'v', "Write info about progress and packing result. Use many -v for more verbosity!",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -273,7 +288,8 @@ static struct my_option my_long_options[] =
static void print_version(void)
{
- printf("%s Ver 1.22 for %s on %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
+ VOID(printf("%s Ver 1.23 for %s on %s\n",
+ my_progname, SYSTEM_TYPE, MACHINE_TYPE));
NETWARE_SET_SCREEN_MODE(1);
}
@@ -290,7 +306,7 @@ static void usage(void)
puts("afterwards to update the keys.");
puts("You should give the .MYI file as the filename argument.");
- printf("\nUsage: %s [OPTIONS] filename...\n", my_progname);
+ VOID(printf("\nUsage: %s [OPTIONS] filename...\n", my_progname));
my_print_help(my_long_options);
print_defaults("my", load_default_groups);
my_print_variables(my_long_options);
@@ -314,7 +330,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
silent= 1;
break;
case 't':
- test_only= verbose= 1;
+ test_only= 1;
+ /* Avoid to reset 'verbose' if it was already set > 1. */
+ if (! verbose)
+ verbose= 1;
break;
case 'T':
length= (uint) (strmov(tmp_dir, argument) - tmp_dir);
@@ -325,7 +344,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
break;
case 'v':
- verbose= 1;
+ verbose++; /* Allow for selecting the level of verbosity. */
silent= 0;
break;
case '#':
@@ -380,7 +399,7 @@ static MI_INFO *open_isam_file(char *name,int mode)
(opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
HA_OPEN_ABORT_IF_LOCKED))))
{
- VOID(fprintf(stderr,"%s gave error %d on open\n",name,my_errno));
+ VOID(fprintf(stderr, "%s gave error %d on open\n", name, my_errno));
DBUG_RETURN(0);
}
share=isam_file->s;
@@ -388,7 +407,7 @@ static MI_INFO *open_isam_file(char *name,int mode)
{
if (!force_pack)
{
- VOID(fprintf(stderr,"%s is already compressed\n",name));
+ VOID(fprintf(stderr, "%s is already compressed\n", name));
VOID(mi_close(isam_file));
DBUG_RETURN(0);
}
@@ -400,7 +419,7 @@ static MI_INFO *open_isam_file(char *name,int mode)
(share->state.state.records <= 1 ||
share->state.state.data_file_length < 1024))
{
- VOID(fprintf(stderr,"%s is too small to compress\n",name));
+ VOID(fprintf(stderr, "%s is too small to compress\n", name));
VOID(mi_close(isam_file));
DBUG_RETURN(0);
}
@@ -446,8 +465,8 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count)
return 0;
diff_file:
- fprintf(stderr,"%s: Tables '%s' and '%s' are not identical\n",
- my_progname,names[j],names[j+1]);
+ VOID(fprintf(stderr, "%s: Tables '%s' and '%s' are not identical\n",
+ my_progname, names[j], names[j+1]));
error:
while (i--)
mi_close(mrg->file[i]);
@@ -518,16 +537,25 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
mrg->records=0;
for (i=0 ; i < mrg->count ; i++)
mrg->records+=mrg->file[i]->s->state.state.records;
+
+ DBUG_PRINT("info", ("Compressing %s: (%lu records)",
+ result_table ? new_name : org_name,
+ (ulong) mrg->records));
if (write_loop || verbose)
{
- printf("Compressing %s: (%lu records)\n",
- result_table ? new_name : org_name,(ulong) mrg->records);
+ VOID(printf("Compressing %s: (%lu records)\n",
+ result_table ? new_name : org_name, (ulong) mrg->records));
}
trees=fields=share->base.fields;
huff_counts=init_huff_count(isam_file,mrg->records);
QUICK_SAFEMALLOC;
+
+ /*
+ Read the whole data file(s) for statistics.
+ */
+ DBUG_PRINT("info", ("- Calculating statistics"));
if (write_loop || verbose)
- printf("- Calculating statistics\n");
+ VOID(printf("- Calculating statistics\n"));
if (get_statistic(mrg,huff_counts))
goto err;
NORMAL_SAFEMALLOC;
@@ -536,29 +564,74 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
old_length+= (mrg->file[i]->s->state.state.data_file_length -
mrg->file[i]->s->state.state.empty);
+ /*
+ Create a global priority queue in preparation for making
+ temporary Huffman trees.
+ */
if (init_queue(&queue,256,0,0,compare_huff_elements,0))
goto err;
+
+ /*
+ Check each column if we should use pre-space-compress, end-space-
+ compress, empty-field-compress or zero-field-compress.
+ */
check_counts(huff_counts,fields,mrg->records);
+
+ /*
+ Build a Huffman tree for each column.
+ */
huff_trees=make_huff_trees(huff_counts,trees);
+
+ /*
+ If the packed lengths of combined columns is less then the sum of
+ the non-combined columns, then create common Huffman trees for them.
+ We do this only for byte compressed columns, not for distinct values
+ compressed columns.
+ */
if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
goto err;
+
+ /*
+ Assign codes to all byte or column values.
+ */
if (make_huff_decode_table(huff_trees,fields))
goto err;
+ /* Prepare a file buffer. */
init_file_buffer(new_file,0);
+
+ /*
+ Reserve space in the target file for the fixed compressed file header.
+ */
file_buffer.pos_in_file=HEAD_LENGTH;
if (! test_only)
VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
+ /*
+ Write field infos: field type, pack type, length bits, tree number.
+ */
write_field_info(huff_counts,fields,used_trees);
+
+ /*
+ Write decode trees.
+ */
if (!(tot_elements=write_huff_tree(huff_trees,trees)))
goto err;
+
+ /*
+ Calculate the total length of the compression info header.
+ This includes the fixed compressed file header, the column compression
+ type descriptions, and the decode trees.
+ */
header_length=(uint) file_buffer.pos_in_file+
(uint) (file_buffer.pos-file_buffer.buffer);
- /* Compress file */
+ /*
+ Compress the source file into the target file.
+ */
+ DBUG_PRINT("info", ("- Compressing file"));
if (write_loop || verbose)
- printf("- Compressing file\n");
+ VOID(printf("- Compressing file\n"));
error=compress_isam_file(mrg,huff_counts);
new_length=file_buffer.pos_in_file;
if (!error && !test_only)
@@ -568,16 +641,28 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
error=my_write(file_buffer.file,buff,sizeof(buff),
MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
}
+
+ /*
+ Write the fixed compressed file header.
+ */
if (!error)
error=write_header(mrg,header_length,used_trees,tot_elements,
new_length);
+
+ /* Flush the file buffer. */
end_file_buffer();
+ /* Display statistics. */
+ DBUG_PRINT("info", ("Min record length: %6d Max length: %6d "
+ "Mean total length: %6ld\n",
+ mrg->min_pack_length, mrg->max_pack_length,
+ (ulong) (mrg->records ? (new_length/mrg->records) : 0)));
if (verbose && mrg->records)
- printf("Min record length: %6d Max length: %6d Mean total length: %6ld\n",
- mrg->min_pack_length,mrg->max_pack_length,
- (ulong) (new_length/mrg->records));
+ VOID(printf("Min record length: %6d Max length: %6d "
+ "Mean total length: %6ld\n", mrg->min_pack_length,
+ mrg->max_pack_length, (ulong) (new_length/mrg->records)));
+ /* Close source and target file. */
if (!test_only)
{
error|=my_close(new_file,MYF(MY_WME));
@@ -588,6 +673,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
}
}
+ /* Cleanup. */
free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
if (! test_only && ! error)
{
@@ -629,15 +715,16 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
error|=my_close(join_isam_file,MYF(MY_WME));
if (error)
{
- VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name));
+ VOID(fprintf(stderr, "Aborting: %s is not compressed\n", org_name));
VOID(my_delete(new_name,MYF(MY_WME)));
DBUG_RETURN(-1);
}
if (write_loop || verbose)
{
if (old_length)
- printf("%.4g%% \n", (((longlong) (old_length -new_length))*100.0/
- (longlong) old_length));
+ VOID(printf("%.4g%% \n",
+ (((longlong) (old_length - new_length)) * 100.0 /
+ (longlong) old_length)));
else
puts("Empty file saved in compressed format");
}
@@ -650,7 +737,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
if (join_isam_file >= 0)
VOID(my_close(join_isam_file,MYF(0)));
mrg_close(mrg);
- VOID(fprintf(stderr,"Aborted: %s is not compressed\n",org_name));
+ VOID(fprintf(stderr, "Aborted: %s is not compressed\n", org_name));
DBUG_RETURN(-1);
}
@@ -677,6 +764,12 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records)
(type == FIELD_NORMAL ||
type == FIELD_SKIP_ZERO))
count[i].max_zero_fill= count[i].field_length;
+ /*
+ For every column initialize a tree, which is used to detect distinct
+ column values. 'int_tree' works together with 'tree_buff' and
+ 'tree_pos'. It's keys are implemented by pointers into 'tree_buff'.
+ This is accomplished by '-1' as the element size.
+ */
init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, NULL,
NULL);
if (records && type != FIELD_BLOB && type != FIELD_VARCHAR)
@@ -762,10 +855,13 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
ulong tot_blob_length=0;
if (! error)
{
+ /* glob_crc is a checksum over all bytes of all records. */
if (static_row_size)
glob_crc+=mi_static_checksum(mrg->file[0],record);
else
glob_crc+=mi_checksum(mrg->file[0],record);
+
+ /* Count the incidence of values separately for every column. */
for (pos=record,count=huff_counts ;
count < end_count ;
count++,
@@ -773,15 +869,48 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
{
next_pos=end_pos=(start_pos=pos)+count->field_length;
- /* Put value in tree if there is room for it */
+ /*
+ Put the whole column value in a tree if there is room for it.
+ 'int_tree' is used to quickly check for duplicate values.
+ 'tree_buff' collects as many distinct column values as
+ possible. If the field length is > 1, it is tree_buff_length,
+ else 2 bytes. Each value is 'field_length' bytes big. If there
+ are more distinct column values than fit into the buffer, we
+ give up with this tree. BLOBs and VARCHARs do not have a
+ tree_buff as it can only be used with fixed length columns.
+ For the special case of field length == 1, we handle only the
+ case that there is only one distinct value in the table(s).
+ Otherwise, we can have a maximum of 256 distinct values. This
+ is then handled by the normal Huffman tree build.
+
+ Another limit for collecting distinct column values is the
+ number of values itself. Since we would need to build a
+ Huffman tree for the values, we are limited by the 'IS_OFFSET'
+ constant. This constant expresses a bit which is used to
+ determine if a tree element holds a final value or an offset
+ to a child element. Hence, all values and offsets need to be
+ smaller than 'IS_OFFSET'. A tree element is implemented with
+ two integer values, one for the left branch and one for the
+ right branch. For the extreme case that the first element
+ points to the last element, the number of integers in the tree
+ must be less or equal to IS_OFFSET. So the number of elements
+ must be less or equal to IS_OFFSET / 2.
+
+ WARNING: At first, we insert a pointer into the record buffer
+ as the key for the tree. If we got a new distinct value, which
+ is really inserted into the tree, instead of being counted
+ only, we will copy the column value from the record buffer to
+ 'tree_buff' and adjust the key pointer of the tree accordingly.
+ */
if (count->tree_buff)
{
global_count=count;
if (!(element=tree_insert(&count->int_tree,pos, 0,
count->int_tree.custom_arg)) ||
(element->count == 1 &&
- count->tree_buff + tree_buff_length <
- count->tree_pos + count->field_length) ||
+ (count->tree_buff + tree_buff_length <
+ count->tree_pos + count->field_length)) ||
+ (count->int_tree.elements_in_tree > IS_OFFSET / 2) ||
(count->field_length == 1 &&
count->int_tree.elements_in_tree > 1))
{
@@ -791,10 +920,17 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
}
else
{
+ /*
+ If tree_insert() succeeds, it either creates a new element
+ or increments the counter of an existing element.
+ */
if (element->count == 1)
- { /* New element */
+ {
+ /* Copy the new column value into 'tree_buff'. */
memcpy(count->tree_pos,pos,(size_t) count->field_length);
+ /* Adjust the key pointer in the tree. */
tree_set_pointer(element,count->tree_pos);
+ /* Point behind the last column value so far. */
count->tree_pos+=count->field_length;
}
}
@@ -804,15 +940,21 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
if (count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_ENDSPACE)
{
+ /* Ignore trailing space. */
for ( ; end_pos > pos ; end_pos--)
if (end_pos[-1] != ' ')
break;
+ /* Empty fields are just counted. Go to the next record. */
if (end_pos == pos)
{
count->empty_fields++;
count->max_zero_fill=0;
continue;
}
+ /*
+ Count the total of all trailing spaces and the number of
+ short trailing spaces. Remember the longest trailing space.
+ */
length= (uint) (next_pos-end_pos);
count->tot_end_space+=length;
if (length < 8)
@@ -820,18 +962,25 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
if (count->max_end_space < length)
count->max_end_space = length;
}
+
if (count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_PRESPACE)
{
+ /* Ignore leading space. */
for (pos=start_pos; pos < end_pos ; pos++)
if (pos[0] != ' ')
break;
+ /* Empty fields are just counted. Go to the next record. */
if (end_pos == pos)
{
count->empty_fields++;
count->max_zero_fill=0;
continue;
}
+ /*
+ Count the total of all leading spaces and the number of
+ short leading spaces. Remember the longest leading space.
+ */
length= (uint) (pos-start_pos);
count->tot_pre_space+=length;
if (length < 8)
@@ -839,6 +988,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
if (count->max_pre_space < length)
count->max_pre_space = length;
}
+
+ /* Calculate pos, end_pos, and max_length for variable length fields. */
if (count->field_type == FIELD_BLOB)
{
uint field_length=count->field_length -mi_portable_sizeof_char_ptr;
@@ -857,45 +1008,121 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
end_pos= pos+length;
set_if_bigger(count->max_length,length);
}
+
+ /* Evaluate 'max_zero_fill' for short fields. */
if (count->field_length <= 8 &&
(count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_ZERO))
{
uint i;
+ /* Zero fields are just counted. Go to the next record. */
if (!memcmp((byte*) start_pos,zero_string,count->field_length))
{
count->zero_fields++;
continue;
}
+ /*
+ max_zero_fill starts with field_length. It is decreased every
+ time a shorter "zero trailer" is found. It is set to zero when
+ an empty field is found (see above). This suggests that the
+ variable should be called 'min_zero_fill'.
+ */
for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
i++) ;
if (i < count->max_zero_fill)
count->max_zero_fill=i;
}
+
+ /* Ignore zero fields and check fields. */
if (count->field_type == FIELD_ZERO ||
count->field_type == FIELD_CHECK)
continue;
+
+ /*
+ Count the incidence of every byte value in the
+ significant field value.
+ */
for ( ; pos < end_pos ; pos++)
count->counts[(uchar) *pos]++;
+
+ /* Step to next field. */
}
+
if (tot_blob_length > max_blob_length)
max_blob_length=tot_blob_length;
record_count++;
if (write_loop && record_count % WRITE_COUNT == 0)
{
- printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ VOID(printf("%lu\r", (ulong) record_count));
+ VOID(fflush(stdout));
}
}
else if (error != HA_ERR_RECORD_DELETED)
{
- fprintf(stderr,"Got error %d while reading rows",error);
+ VOID(fprintf(stderr, "Got error %d while reading rows", error));
break;
}
+
+ /* Step to next record. */
}
if (write_loop)
{
- printf(" \r"); VOID(fflush(stdout));
+ VOID(printf(" \r"));
+ VOID(fflush(stdout));
}
+
+ /*
+ If --debug=d,fakebigcodes is set, fake the counts to get big Huffman
+ codes.
+ */
+ DBUG_EXECUTE_IF("fakebigcodes", fakebigcodes(huff_counts, end_count););
+
+ DBUG_PRINT("info", ("Found the following number of incidents "
+ "of the byte codes:"));
+ if (verbose >= 2)
+ VOID(printf("Found the following number of incidents "
+ "of the byte codes:\n"));
+ for (count= huff_counts ; count < end_count; count++)
+ {
+ uint idx;
+ my_off_t total_count;
+ char llbuf[32];
+
+ DBUG_PRINT("info", ("column: %3u", count - huff_counts + 1));
+ if (verbose >= 2)
+ VOID(printf("column: %3u\n", count - huff_counts + 1));
+ if (count->tree_buff)
+ {
+ DBUG_PRINT("info", ("number of distinct values: %u",
+ (count->tree_pos - count->tree_buff) /
+ count->field_length));
+ if (verbose >= 2)
+ VOID(printf("number of distinct values: %u\n",
+ (count->tree_pos - count->tree_buff) /
+ count->field_length));
+ }
+ total_count= 0;
+ for (idx= 0; idx < 256; idx++)
+ {
+ if (count->counts[idx])
+ {
+ total_count+= count->counts[idx];
+ DBUG_PRINT("info", ("counts[0x%02x]: %12s", idx,
+ llstr((longlong) count->counts[idx], llbuf)));
+ if (verbose >= 2)
+ VOID(printf("counts[0x%02x]: %12s\n", idx,
+ llstr((longlong) count->counts[idx], llbuf)));
+ }
+ }
+ DBUG_PRINT("info", ("total: %12s", llstr((longlong) total_count,
+ llbuf)));
+ if ((verbose >= 2) && total_count)
+ {
+ VOID(printf("total: %12s\n",
+ llstr((longlong) total_count, llbuf)));
+ }
+ }
+
mrg->records=record_count;
mrg->max_blob_length=max_blob_length;
my_afree((gptr) record);
@@ -944,9 +1171,14 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
huff_counts->field_type=FIELD_NORMAL;
huff_counts->pack_type=0;
+ /* Check for zero-filled records (in this column), or zero records. */
if (huff_counts->zero_fields || ! records)
{
my_off_t old_space_count;
+ /*
+ If there are only zero filled records (in this column),
+ or no records at all, we are done.
+ */
if (huff_counts->zero_fields == records)
{
huff_counts->field_type= FIELD_ZERO;
@@ -954,14 +1186,22 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
huff_counts->counts[0]=0;
goto found_pack;
}
+ /* Remeber the number of significant spaces. */
old_space_count=huff_counts->counts[' '];
- huff_counts->counts[' ']+=huff_counts->tot_end_space+
- huff_counts->tot_pre_space +
- huff_counts->empty_fields * huff_counts->field_length;
+ /* Add all leading and trailing spaces. */
+ huff_counts->counts[' ']+= (huff_counts->tot_end_space +
+ huff_counts->tot_pre_space +
+ huff_counts->empty_fields *
+ huff_counts->field_length);
+ /* Check, what the compressed length of this would be. */
old_length=calc_packed_length(huff_counts,0)+records/8;
+ /* Get the number of zero bytes. */
length=huff_counts->zero_fields*huff_counts->field_length;
+ /* Add it to the counts. */
huff_counts->counts[0]+=length;
+ /* Check, what the compressed length of this would be. */
new_length=calc_packed_length(huff_counts,0);
+ /* If the compression without the zeroes would be shorter, we are done. */
if (old_length < new_length && huff_counts->field_length > 1)
{
huff_counts->field_type=FIELD_SKIP_ZERO;
@@ -969,9 +1209,16 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
huff_counts->bytes_packed=old_length- records/8;
goto found_pack;
}
+ /* Remove the insignificant spaces, but keep the zeroes. */
huff_counts->counts[' ']=old_space_count;
}
+ /* Check, what the compressed length of this column would be. */
huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+
+ /*
+ If there are enough empty records (in this column),
+ treating them specially may pay off.
+ */
if (huff_counts->empty_fields)
{
if (huff_counts->field_length > 2 &&
@@ -1003,6 +1250,11 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
}
}
}
+
+ /*
+ If there are enough trailing spaces (in this column),
+ treating them specially may pay off.
+ */
if (huff_counts->tot_end_space)
{
huff_counts->counts[' ']+=huff_counts->tot_pre_space;
@@ -1012,6 +1264,11 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
goto found_pack;
huff_counts->counts[' ']-=huff_counts->tot_pre_space;
}
+
+ /*
+ If there are enough leading spaces (in this column),
+ treating them specially may pay off.
+ */
if (huff_counts->tot_pre_space)
{
if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
@@ -1041,6 +1298,8 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
{
HUFF_TREE tree;
+ DBUG_EXECUTE_IF("forceintervall",
+ huff_counts->bytes_packed= ~ (my_off_t) 0;);
tree.element_buffer=0;
if (!make_huff_tree(&tree,huff_counts) &&
tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
@@ -1066,14 +1325,27 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
fill_zero_fields++;
field_count[huff_counts->field_type]++;
}
+ DBUG_PRINT("info", ("normal: %3d empty-space: %3d "
+ "empty-zero: %3d empty-fill: %3d",
+ field_count[FIELD_NORMAL],space_fields,
+ field_count[FIELD_SKIP_ZERO],fill_zero_fields));
+ DBUG_PRINT("info", ("pre-space: %3d end-space: %3d "
+ "intervall-fields: %3d zero: %3d",
+ field_count[FIELD_SKIP_PRESPACE],
+ field_count[FIELD_SKIP_ENDSPACE],
+ field_count[FIELD_INTERVALL],
+ field_count[FIELD_ZERO]));
if (verbose)
- printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d intervall-fields: %3d zero: %3d\n",
- field_count[FIELD_NORMAL],space_fields,
- field_count[FIELD_SKIP_ZERO],fill_zero_fields,
- field_count[FIELD_SKIP_PRESPACE],
- field_count[FIELD_SKIP_ENDSPACE],
- field_count[FIELD_INTERVALL],
- field_count[FIELD_ZERO]);
+ VOID(printf("\nnormal: %3d empty-space: %3d "
+ "empty-zero: %3d empty-fill: %3d\n"
+ "pre-space: %3d end-space: %3d "
+ "intervall-fields: %3d zero: %3d\n",
+ field_count[FIELD_NORMAL],space_fields,
+ field_count[FIELD_SKIP_ZERO],fill_zero_fields,
+ field_count[FIELD_SKIP_PRESPACE],
+ field_count[FIELD_SKIP_ENDSPACE],
+ field_count[FIELD_INTERVALL],
+ field_count[FIELD_ZERO]));
DBUG_VOID_RETURN;
}
@@ -1170,8 +1442,24 @@ static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
DBUG_RETURN(huff_tree);
}
- /* Update huff_tree according to huff_counts->counts or
- huff_counts->tree_buff */
+/*
+ Build a Huffman tree.
+
+ SYNOPSIS
+ make_huff_tree()
+ huff_tree The Huffman tree.
+ huff_counts The counts.
+
+ DESCRIPTION
+ Build a Huffman tree according to huff_counts->counts or
+ huff_counts->tree_buff. tree_buff, if non-NULL contains up to
+ tree_buff_length of distinct column values. In that case, whole
+ values can be Huffman encoded instead of single bytes.
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
{
@@ -1182,12 +1470,14 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
first=last=0;
if (huff_counts->tree_buff)
{
+ /* Calculate the number of distinct values in tree_buff. */
found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
huff_counts->field_length;
first=0; last=found-1;
}
else
{
+ /* Count the number of byte codes found in the column. */
for (i=found=0 ; i < 256 ; i++)
{
if (huff_counts->counts[i])
@@ -1201,6 +1491,7 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
found=2;
}
+ /* When using 'tree_buff' we can have more that 256 values. */
if (queue.max_elements < found)
{
delete_queue(&queue);
@@ -1208,6 +1499,7 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
return -1;
}
+ /* Allocate or reallocate an element buffer for the Huffman tree. */
if (!huff_tree->element_buffer)
{
if (!(huff_tree->element_buffer=
@@ -1235,15 +1527,25 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
if (huff_counts->tree_buff)
{
huff_tree->elements=0;
- tree_walk(&huff_counts->int_tree,
- (int (*)(void*, element_count,void*)) save_counts_in_queue,
- (gptr) huff_tree, left_root_right);
huff_tree->tree_pack_length=(1+15+16+5+5+
(huff_tree->char_bits+1)*found+
(huff_tree->offset_bits+1)*
(found-2)+7)/8 +
(uint) (huff_tree->counts->tree_pos-
huff_tree->counts->tree_buff);
+ /*
+ Put a HUFF_ELEMENT into the queue for every distinct column value.
+
+ tree_walk() calls save_counts_in_queue() for every element in
+ 'int_tree'. This takes elements from the target trees element
+ buffer and places references to them into the buffer of the
+ priority queue. We insert in column value order, but the order is
+ in fact irrelevant here. We will establish the correct order
+ later.
+ */
+ tree_walk(&huff_counts->int_tree,
+ (int (*)(void*, element_count,void*)) save_counts_in_queue,
+ (gptr) huff_tree, left_root_right);
}
else
{
@@ -1252,7 +1554,15 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
(huff_tree->char_bits+1)*found+
(huff_tree->offset_bits+1)*
(found-2)+7)/8;
+ /*
+ Put a HUFF_ELEMENT into the queue for every byte code found in the column.
+ The elements are taken from the target trees element buffer.
+ Instead of using queue_insert(), we just place references to the
+ elements into the buffer of the priority queue. We insert in byte
+ value order, but the order is in fact irrelevant here. We will
+ establish the correct order later.
+ */
for (i=first, found=0 ; i <= last ; i++)
{
if (huff_counts->counts[i])
@@ -1264,8 +1574,13 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
queue.root[found]=(byte*) new_huff_el;
}
}
+ /*
+ If there is only a single byte value in this field in all records,
+ add a second element with zero incidence. This is required to enter
+ the loop, which builds the Huffman tree.
+ */
while (found < 2)
- { /* Our huff_trees request at least 2 elements */
+ {
new_huff_el=huff_tree->element_buffer+(found++);
new_huff_el->count=0;
new_huff_el->a.leaf.null=0;
@@ -1276,21 +1591,53 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
queue.root[found]=(byte*) new_huff_el;
}
}
+
+ /* Make a queue from the queue buffer. */
queue.elements=found;
+ /*
+ Make a priority queue from the queue. Construct its index so that we
+ have a partially ordered tree.
+ */
for (i=found/2 ; i > 0 ; i--)
_downheap(&queue,i);
+
+ /* The Huffman algorithm. */
bytes_packed=0; bits_packed=0;
for (i=1 ; i < found ; i++)
{
+ /*
+ Pop the top element from the queue (the one with the least incidence).
+ Popping from a priority queue includes a re-ordering of the queue,
+ to get the next least incidence element to the top.
+ */
a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ /*
+ Copy the next least incidence element. The queue implementation
+ reserves root[0] for temporary purposes. root[1] is the top.
+ */
b=(HUFF_ELEMENT*) queue.root[1];
+ /* Get a new element from the element buffer. */
new_huff_el=huff_tree->element_buffer+found+i;
+ /* The new element gets the sum of the two least incidence elements. */
new_huff_el->count=a->count+b->count;
+ /*
+ The Huffman algorithm assigns another bit to the code for a byte
+ every time that bytes incidence is combined (directly or indirectly)
+ to a new element as one of the two least incidence elements.
+ This means that one more bit per incidence of that byte is required
+ in the resulting file. So we add the new combined incidence as the
+ number of bits by which the result grows.
+ */
bits_packed+=(uint) (new_huff_el->count & 7);
bytes_packed+=new_huff_el->count/8;
- new_huff_el->a.nod.left=a; /* lesser in left */
+ /* The new element points to its children, lesser in left. */
+ new_huff_el->a.nod.left=a;
new_huff_el->a.nod.right=b;
+ /*
+ Replace the copied top element by the new element and re-order the
+ queue.
+ */
queue.root[1]=(byte*) new_huff_el;
queue_replaced(&queue);
}
@@ -1309,7 +1656,26 @@ static int compare_tree(void* cmp_arg __attribute__((unused)),
return 0;
}
- /* Used by make_huff_tree to save intervall-counts in queue */
+/*
+ Organize distinct column values and their incidences into a priority queue.
+
+ SYNOPSIS
+ save_counts_in_queue()
+ key The column value.
+ count The incidence of this value.
+ tree The Huffman tree to be built later.
+
+ DESCRIPTION
+ We use the element buffer of the targeted tree. The distinct column
+ values are organized in a priority queue first. The Huffman
+ algorithm will later organize the elements into a Huffman tree. For
+ the time being, we just place references to the elements into the
+ queue buffer. The buffer will later be organized into a priority
+ queue.
+
+ RETURN
+ 0
+ */
static int save_counts_in_queue(byte *key, element_count count,
HUFF_TREE *tree)
@@ -1326,8 +1692,23 @@ static int save_counts_in_queue(byte *key, element_count count,
}
- /* Calculate length of file if given counts should be used */
- /* Its actually a faster version of make_huff_tree */
+/*
+ Calculate length of file if given counts should be used.
+
+ SYNOPSIS
+ calc_packed_length()
+ huff_counts The counts for a column of the table(s).
+ add_tree_lenght If the decode tree length should be added.
+
+ DESCRIPTION
+ We need to follow the Huffman algorithm until we know, how many bits
+ are required for each byte code. But we do not need the resulting
+ Huffman tree. Hence, we can leave out some steps which are essential
+ in make_huff_tree().
+
+ RETURN
+ Number of bytes required to compress this table column.
+*/
static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
uint add_tree_lenght)
@@ -1337,6 +1718,23 @@ static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
HUFF_ELEMENT element_buffer[256];
DBUG_ENTER("calc_packed_length");
+ /*
+ WARNING: We use a small hack for efficiency: Instead of placing
+ references to HUFF_ELEMENTs into the queue, we just insert
+ references to the counts of the byte codes which appeared in this
+ table column. During the Huffman algorithm they are successively
+ replaced by references to HUFF_ELEMENTs. This works, because
+ HUFF_ELEMENTs have the incidence count at their beginning.
+ Regardless, wether the queue array contains references to counts of
+ type my_off_t or references to HUFF_ELEMENTs which have the count of
+ type my_off_t at their beginning, it always points to a count of the
+ same type.
+
+ Instead of using queue_insert(), we just copy the references into
+ the buffer of the priority queue. We insert in byte value order, but
+ the order is in fact irrelevant here. We will establish the correct
+ order later.
+ */
first=last=0;
for (i=found=0 ; i < 256 ; i++)
{
@@ -1345,31 +1743,73 @@ static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
if (! found++)
first=i;
last=i;
+ /* We start with root[1], which is the queues top element. */
queue.root[found]=(byte*) &huff_counts->counts[i];
}
}
if (!found)
DBUG_RETURN(0); /* Empty tree */
+ /*
+ If there is only a single byte value in this field in all records,
+ add a second element with zero incidence. This is required to enter
+ the loop, which follows the Huffman algorithm.
+ */
if (found < 2)
queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
+ /* Make a queue from the queue buffer. */
queue.elements=found;
bytes_packed=0; bits_packed=0;
+ /* Add the length of the coding table, which would become part of the file. */
if (add_tree_lenght)
bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
(max_bit(found-1)+1+1)*(found-2) +7)/8;
+
+ /*
+ Make a priority queue from the queue. Construct its index so that we
+ have a partially ordered tree.
+ */
for (i=(found+1)/2 ; i > 0 ; i--)
_downheap(&queue,i);
+
+ /* The Huffman algorithm. */
for (i=0 ; i < found-1 ; i++)
{
- HUFF_ELEMENT *a,*b,*new_huff_el;
- a=(HUFF_ELEMENT*) queue_remove(&queue,0);
- b=(HUFF_ELEMENT*) queue.root[1];
- new_huff_el=element_buffer+i;
- new_huff_el->count=a->count+b->count;
+ my_off_t *a;
+ my_off_t *b;
+ HUFF_ELEMENT *new_huff_el;
+
+ /*
+ Pop the top element from the queue (the one with the least
+ incidence). Popping from a priority queue includes a re-ordering
+ of the queue, to get the next least incidence element to the top.
+ */
+ a= (my_off_t*) queue_remove(&queue, 0);
+ /*
+ Copy the next least incidence element. The queue implementation
+ reserves root[0] for temporary purposes. root[1] is the top.
+ */
+ b= (my_off_t*) queue.root[1];
+ /* Create a new element in a local (automatic) buffer. */
+ new_huff_el= element_buffer + i;
+ /* The new element gets the sum of the two least incidence elements. */
+ new_huff_el->count= *a + *b;
+ /*
+ The Huffman algorithm assigns another bit to the code for a byte
+ every time that bytes incidence is combined (directly or indirectly)
+ to a new element as one of the two least incidence elements.
+ This means that one more bit per incidence of that byte is required
+ in the resulting file. So we add the new combined incidence as the
+ number of bits by which the result grows.
+ */
bits_packed+=(uint) (new_huff_el->count & 7);
bytes_packed+=new_huff_el->count/8;
+ /*
+ Replace the copied top element by the new element and re-order the
+ queue. This successively replaces the references to counts by
+ references to HUFF_ELEMENTs.
+ */
queue.root[1]=(byte*) new_huff_el;
queue_replaced(&queue);
}
@@ -1417,13 +1857,26 @@ static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
}
}
}
+ DBUG_PRINT("info", ("Original trees: %d After join: %d",
+ trees, tree_number));
if (verbose)
- printf("Original trees: %d After join: %d\n",trees,tree_number);
+ VOID(printf("Original trees: %d After join: %d\n", trees, tree_number));
return tree_number; /* Return trees left */
}
- /* Fill in huff_tree decode tables */
+/*
+ Fill in huff_tree encode tables.
+
+ SYNOPSIS
+ make_huff_decode_table()
+ huff_tree An array of HUFF_TREE which are to be encoded.
+ trees The number of HUFF_TREE in the array.
+
+ RETURN
+ 0 success
+ != 0 error
+*/
static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
{
@@ -1434,12 +1887,13 @@ static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
{
elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
if (!(huff_tree->code =
- (ulong*) my_malloc(elements*
- (sizeof(ulong)+sizeof(uchar)),
- MYF(MY_WME | MY_ZEROFILL))))
+ (ulonglong*) my_malloc(elements*
+ (sizeof(ulonglong) + sizeof(uchar)),
+ MYF(MY_WME | MY_ZEROFILL))))
return 1;
huff_tree->code_len=(uchar*) (huff_tree->code+elements);
- make_traverse_code_tree(huff_tree,huff_tree->root,32,0);
+ make_traverse_code_tree(huff_tree, huff_tree->root,
+ 8 * sizeof(ulonglong), LL(0));
}
}
return 0;
@@ -1448,28 +1902,90 @@ static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
static void make_traverse_code_tree(HUFF_TREE *huff_tree,
HUFF_ELEMENT *element,
- uint size, ulong code)
+ uint size, ulonglong code)
{
uint chr;
if (!element->a.leaf.null)
{
chr=element->a.leaf.element_nr;
- huff_tree->code_len[chr]=(uchar) (32-size);
- huff_tree->code[chr]= (code >> size);
- if (huff_tree->height < 32-size)
- huff_tree->height= 32-size;
+ huff_tree->code_len[chr]= (uchar) (8 * sizeof(ulonglong) - size);
+ huff_tree->code[chr]= (code >> size);
+ if (huff_tree->height < 8 * sizeof(ulonglong) - size)
+ huff_tree->height= 8 * sizeof(ulonglong) - size;
}
else
{
size--;
make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
- make_traverse_code_tree(huff_tree,element->a.nod.right,size,
- code+((ulong) 1L << size));
+ make_traverse_code_tree(huff_tree, element->a.nod.right, size,
+ code + (((ulonglong) 1) << size));
}
return;
}
+/*
+ Convert a value into binary digits.
+
+ SYNOPSIS
+ bindigits()
+ value The value.
+ length The number of low order bits to convert.
+
+ NOTE
+ The result string is in static storage. It is reused on every call.
+ So you cannot use it twice in one expression.
+
+ RETURN
+ A pointer to a static NUL-terminated string.
+ */
+
+static char *bindigits(ulonglong value, uint bits)
+{
+ static char digits[72];
+ char *ptr= digits;
+ uint idx= bits;
+
+ DBUG_ASSERT(idx < sizeof(digits));
+ while (idx)
+ *(ptr++)= '0' + ((value >> (--idx)) & 1);
+ *ptr= '\0';
+ return digits;
+}
+
+
+/*
+ Convert a value into hexadecimal digits.
+
+ SYNOPSIS
+ hexdigits()
+ value The value.
+
+ NOTE
+ The result string is in static storage. It is reused on every call.
+ So you cannot use it twice in one expression.
+
+ RETURN
+ A pointer to a static NUL-terminated string.
+ */
+
+static char *hexdigits(ulonglong value)
+{
+ static char digits[20];
+ char *ptr= digits;
+ uint idx= 2 * sizeof(value); /* Two hex digits per byte. */
+
+ DBUG_ASSERT(idx < sizeof(digits));
+ while (idx)
+ {
+ if ((*(ptr++)= '0' + ((value >> (4 * (--idx))) & 0xf)) > '9')
+ *(ptr - 1)+= 'a' - '9' - 1;
+ }
+ *ptr= '\0';
+ return digits;
+}
+
+
/* Write header to new packed data file */
static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees,
@@ -1503,15 +2019,64 @@ static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
uint huff_tree_bits;
huff_tree_bits=max_bit(trees ? trees-1 : 0);
+ DBUG_PRINT("info", (""));
+ DBUG_PRINT("info", ("column types:"));
+ DBUG_PRINT("info", ("FIELD_NORMAL 0"));
+ DBUG_PRINT("info", ("FIELD_SKIP_ENDSPACE 1"));
+ DBUG_PRINT("info", ("FIELD_SKIP_PRESPACE 2"));
+ DBUG_PRINT("info", ("FIELD_SKIP_ZERO 3"));
+ DBUG_PRINT("info", ("FIELD_BLOB 4"));
+ DBUG_PRINT("info", ("FIELD_CONSTANT 5"));
+ DBUG_PRINT("info", ("FIELD_INTERVALL 6"));
+ DBUG_PRINT("info", ("FIELD_ZERO 7"));
+ DBUG_PRINT("info", ("FIELD_VARCHAR 8"));
+ DBUG_PRINT("info", ("FIELD_CHECK 9"));
+ DBUG_PRINT("info", (""));
+ DBUG_PRINT("info", ("pack type as a set of flags:"));
+ DBUG_PRINT("info", ("PACK_TYPE_SELECTED 1"));
+ DBUG_PRINT("info", ("PACK_TYPE_SPACE_FIELDS 2"));
+ DBUG_PRINT("info", ("PACK_TYPE_ZERO_FILL 4"));
+ DBUG_PRINT("info", (""));
+ if (verbose >= 2)
+ {
+ VOID(printf("\n"));
+ VOID(printf("column types:\n"));
+ VOID(printf("FIELD_NORMAL 0\n"));
+ VOID(printf("FIELD_SKIP_ENDSPACE 1\n"));
+ VOID(printf("FIELD_SKIP_PRESPACE 2\n"));
+ VOID(printf("FIELD_SKIP_ZERO 3\n"));
+ VOID(printf("FIELD_BLOB 4\n"));
+ VOID(printf("FIELD_CONSTANT 5\n"));
+ VOID(printf("FIELD_INTERVALL 6\n"));
+ VOID(printf("FIELD_ZERO 7\n"));
+ VOID(printf("FIELD_VARCHAR 8\n"));
+ VOID(printf("FIELD_CHECK 9\n"));
+ VOID(printf("\n"));
+ VOID(printf("pack type as a set of flags:\n"));
+ VOID(printf("PACK_TYPE_SELECTED 1\n"));
+ VOID(printf("PACK_TYPE_SPACE_FIELDS 2\n"));
+ VOID(printf("PACK_TYPE_ZERO_FILL 4\n"));
+ VOID(printf("\n"));
+ }
for (i=0 ; i++ < fields ; counts++)
{
- write_bits((ulong) (int) counts->field_type,5);
+ write_bits((ulonglong) (int) counts->field_type, 5);
write_bits(counts->pack_type,6);
if (counts->pack_type & PACK_TYPE_ZERO_FILL)
write_bits(counts->max_zero_fill,5);
else
write_bits(counts->length_bits,5);
- write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
+ write_bits((ulonglong) counts->tree->tree_number - 1, huff_tree_bits);
+ DBUG_PRINT("info", ("column: %3u type: %2u pack: %2u zero: %4u "
+ "lbits: %2u tree: %2u length: %4u",
+ i , counts->field_type, counts->pack_type,
+ counts->max_zero_fill, counts->length_bits,
+ counts->tree->tree_number, counts->field_length));
+ if (verbose >= 2)
+ VOID(printf("column: %3u type: %2u pack: %2u zero: %4u lbits: %2u "
+ "tree: %2u length: %4u\n", i , counts->field_type,
+ counts->pack_type, counts->max_zero_fill, counts->length_bits,
+ counts->tree->tree_number, counts->field_length));
}
flush_bits();
return;
@@ -1524,45 +2089,72 @@ static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
{
uint i,int_length;
+ uint tree_no;
+ uint codes;
+ uint errors= 0;
uint *packed_tree,*offset,length;
my_off_t elements;
+ /* Find the highest number of elements in the trees. */
for (i=length=0 ; i < trees ; i++)
if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
length=huff_tree[i].elements;
+ /*
+ Allocate a buffer for packing a decode tree. Two numbers per element
+ (left child and right child).
+ */
if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
{
my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
return 0;
}
+ DBUG_PRINT("info", (""));
+ if (verbose >= 2)
+ VOID(printf("\n"));
+ tree_no= 0;
intervall_length=0;
for (elements=0; trees-- ; huff_tree++)
{
+ /* Skip columns that have been joined with other columns. */
if (huff_tree->tree_number == 0)
continue; /* Deleted tree */
+ tree_no++;
+ DBUG_PRINT("info", (""));
+ if (verbose >= 3)
+ VOID(printf("\n"));
+ /* Count the total number of elements (byte codes or column values). */
elements+=huff_tree->elements;
huff_tree->max_offset=2;
+ /* Build a tree of offsets and codes for decoding in 'packed_tree'. */
if (huff_tree->elements <= 1)
offset=packed_tree;
else
offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
+
+ /* This should be the same as 'length' above. */
huff_tree->offset_bits=max_bit(huff_tree->max_offset);
+
+ /*
+ Since we check this during collecting the distinct column values,
+ this should never happen.
+ */
if (huff_tree->max_offset >= IS_OFFSET)
{ /* This should be impossible */
- VOID(fprintf(stderr,"Tree offset got too big: %d, aborted\n",
- huff_tree->max_offset));
+ VOID(fprintf(stderr, "Tree offset got too big: %d, aborted\n",
+ huff_tree->max_offset));
my_afree((gptr) packed_tree);
return 0;
}
-#ifdef EXTRA_DBUG
- printf("pos: %d elements: %d tree-elements: %d char_bits: %d\n",
- (uint) (file_buffer.pos-file_buffer.buffer),
- huff_tree->elements, (offset-packed_tree),huff_tree->char_bits);
-#endif
+ DBUG_PRINT("info", ("pos: %lu elements: %u tree-elements: %lu "
+ "char_bits: %u\n",
+ (ulong) (file_buffer.pos - file_buffer.buffer),
+ huff_tree->elements, (ulong) (offset - packed_tree),
+ huff_tree->char_bits));
if (!huff_tree->counts->tree_buff)
{
+ /* We do a byte compression on this column. Mark with bit 0. */
write_bits(0,1);
write_bits(huff_tree->min_chr,8);
write_bits(huff_tree->elements,9);
@@ -1574,6 +2166,7 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
{
int_length=(uint) (huff_tree->counts->tree_pos -
huff_tree->counts->tree_buff);
+ /* We have distinct column values for this column. Mark with bit 1. */
write_bits(1,1);
write_bits(huff_tree->elements,15);
write_bits(int_length,16);
@@ -1581,10 +2174,29 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
write_bits(huff_tree->offset_bits,5);
intervall_length+=int_length;
}
+ DBUG_PRINT("info", ("tree: %2u elements: %4u char_bits: %2u "
+ "offset_bits: %2u %s: %5u codelen: %2u",
+ tree_no, huff_tree->elements, huff_tree->char_bits,
+ huff_tree->offset_bits, huff_tree->counts->tree_buff ?
+ "bufflen" : "min_chr", huff_tree->counts->tree_buff ?
+ int_length : huff_tree->min_chr, huff_tree->height));
+ if (verbose >= 2)
+ VOID(printf("tree: %2u elements: %4u char_bits: %2u offset_bits: %2u "
+ "%s: %5u codelen: %2u\n", tree_no, huff_tree->elements,
+ huff_tree->char_bits, huff_tree->offset_bits,
+ huff_tree->counts->tree_buff ? "bufflen" : "min_chr",
+ huff_tree->counts->tree_buff ? int_length :
+ huff_tree->min_chr, huff_tree->height));
+
+ /* Check that the code tree length matches the element count. */
length=(uint) (offset-packed_tree);
if (length != huff_tree->elements*2-2)
- printf("error: Huff-tree-length: %d != calc_length: %d\n",
- length,huff_tree->elements*2-2);
+ {
+ VOID(fprintf(stderr, "error: Huff-tree-length: %d != calc_length: %d\n",
+ length, huff_tree->elements * 2 - 2));
+ errors++;
+ break;
+ }
for (i=0 ; i < length ; i++)
{
@@ -1593,16 +2205,122 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
huff_tree->offset_bits+1);
else
write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
+ DBUG_PRINT("info", ("tree[0x%04x]: %s0x%04x",
+ i, (packed_tree[i] & IS_OFFSET) ?
+ " -> " : "", (packed_tree[i] & IS_OFFSET) ?
+ packed_tree[i] - IS_OFFSET + i : packed_tree[i]));
+ if (verbose >= 3)
+ VOID(printf("tree[0x%04x]: %s0x%04x\n",
+ i, (packed_tree[i] & IS_OFFSET) ? " -> " : "",
+ (packed_tree[i] & IS_OFFSET) ?
+ packed_tree[i] - IS_OFFSET + i : packed_tree[i]));
}
flush_bits();
+
+ /*
+ Display coding tables and check their correctness.
+ */
+ codes= huff_tree->counts->tree_buff ? huff_tree->elements : 256;
+ for (i= 0; i < codes; i++)
+ {
+ ulonglong code;
+ uint bits;
+ uint len;
+ uint idx;
+
+ if (! (len= huff_tree->code_len[i]))
+ continue;
+ DBUG_PRINT("info", ("code[0x%04x]: 0x%s bits: %2u bin: %s", i,
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i],
+ bindigits(huff_tree->code[i],
+ huff_tree->code_len[i])));
+ if (verbose >= 3)
+ VOID(printf("code[0x%04x]: 0x%s bits: %2u bin: %s\n", i,
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i],
+ bindigits(huff_tree->code[i], huff_tree->code_len[i])));
+
+ /* Check that the encode table decodes correctly. */
+ code= 0;
+ bits= 0;
+ idx= 0;
+ DBUG_EXECUTE_IF("forcechkerr1", len--;);
+ DBUG_EXECUTE_IF("forcechkerr2", bits= 8 * sizeof(code););
+ DBUG_EXECUTE_IF("forcechkerr3", idx= length;);
+ for (;;)
+ {
+ if (! len)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: code 0x%s with %u bits not found\n",
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i]));
+ errors++;
+ break;
+ }
+ code<<= 1;
+ code|= (huff_tree->code[i] >> (--len)) & 1;
+ bits++;
+ if (bits > 8 * sizeof(code))
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: Huffman code too long: %u/%u\n",
+ bits, 8 * sizeof(code)));
+ errors++;
+ break;
+ }
+ idx+= code & 1;
+ if (idx >= length)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: illegal tree offset: %u/%u\n",
+ idx, length));
+ errors++;
+ break;
+ }
+ if (packed_tree[idx] & IS_OFFSET)
+ idx+= packed_tree[idx] & ~IS_OFFSET;
+ else
+ break; /* Hit a leaf. This contains the result value. */
+ }
+ if (errors)
+ break;
+
+ DBUG_EXECUTE_IF("forcechkerr4", packed_tree[idx]++;);
+ if (packed_tree[idx] != i)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: decoded value 0x%04x should be: 0x%04x\n",
+ packed_tree[idx], i));
+ errors++;
+ break;
+ }
+ } /*end for (codes)*/
+ if (errors)
+ break;
+
+ /* Write column values in case of distinct column value compression. */
if (huff_tree->counts->tree_buff)
{
for (i=0 ; i < int_length ; i++)
- write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
+ {
+ write_bits((ulonglong) (uchar) huff_tree->counts->tree_buff[i], 8);
+ DBUG_PRINT("info", ("column_values[0x%04x]: 0x%02x",
+ i, (uchar) huff_tree->counts->tree_buff[i]));
+ if (verbose >= 3)
+ VOID(printf("column_values[0x%04x]: 0x%02x\n",
+ i, (uchar) huff_tree->counts->tree_buff[i]));
+ }
}
flush_bits();
}
+ DBUG_PRINT("info", (""));
+ if (verbose >= 2)
+ VOID(printf("\n"));
my_afree((gptr) packed_tree);
+ if (errors)
+ {
+ VOID(fprintf(stderr, "Error: Generated decode trees are corrupt. Stop.\n"));
+ return 0;
+ }
return elements;
}
@@ -1613,23 +2331,43 @@ static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
uint *prev_offset;
prev_offset= offset;
+ /*
+ 'a.leaf.null' takes the same place as 'a.nod.left'. If this is null,
+ then there is no left child and, hence no right child either. This
+ is a property of a binary tree. An element is either a node with two
+ childs, or a leaf without childs.
+
+ The current element is always a node with two childs. Go left first.
+ */
if (!element->a.nod.left->a.leaf.null)
{
- offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
+ /* Store the byte code or the index of the column value. */
+ prev_offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
offset+=2;
}
else
{
+ /*
+ Recursively traverse the tree to the left. Mark it as an offset to
+ another tree node (in contrast to a byte code or column value index).
+ */
prev_offset[0]= IS_OFFSET+2;
offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
}
+
+ /* Now, check the right child. */
if (!element->a.nod.right->a.leaf.null)
{
+ /* Store the byte code or the index of the column value. */
prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
return offset;
}
else
{
+ /*
+ Recursively traverse the tree to the right. Mark it as an offset to
+ another tree node (in contrast to a byte code or column value index).
+ */
uint temp=(uint) (offset-prev_offset-1);
prev_offset[1]= IS_OFFSET+ temp;
if (huff_tree->max_offset < temp)
@@ -1656,6 +2394,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
intervall,field_length,max_pack_length,pack_blob_length;
my_off_t record_count;
+ char llbuf[32];
ulong length,pack_length;
byte *record,*pos,*end_pos,*record_pos,*start_pos;
HUFF_COUNTS *count,*end_count;
@@ -1663,12 +2402,23 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
MI_INFO *isam_file=mrg->file[0];
DBUG_ENTER("compress_isam_file");
+ /* Allocate a buffer for the records (excluding blobs). */
if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
return -1;
+
end_count=huff_counts+isam_file->s->base.fields;
min_record_length= (uint) ~0;
max_record_length=0;
+ /*
+ Calculate the maximum number of bits required to pack the records.
+ Remember to understand 'max_zero_fill' as 'min_zero_fill'.
+ The tree height determines the maximum number of bits per value.
+ Some fields skip leading or trailing spaces or zeroes. The skipped
+ number of bytes is encoded by 'length_bits' bits.
+ Empty blobs and varchar are encoded with a single 1 bit. Other blobs
+ and varchar get a leading 0 bit.
+ */
for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
{
if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
@@ -1687,14 +2437,16 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
(huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
huff_counts[i].tree->height+huff_counts[i].length_bits;
}
- max_calc_length/=8;
+ max_calc_length= (max_calc_length + 7) / 8;
if (max_calc_length < 254)
pack_ref_length=1;
else if (max_calc_length <= 65535)
pack_ref_length=3;
else
pack_ref_length=4;
+
record_count=0;
+ /* 'max_blob_length' is the max length of all blobs of a record. */
pack_blob_length=0;
if (isam_file->s->base.blobs)
{
@@ -1707,6 +2459,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
}
max_pack_length=pack_ref_length+pack_blob_length;
+ DBUG_PRINT("fields", ("==="));
mrg_reset(mrg);
while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
{
@@ -1722,15 +2475,29 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
end_pos=start_pos+(field_length=count->field_length);
tree=count->tree;
+ DBUG_PRINT("fields", ("column: %3lu type: %2u pack: %2u zero: %4u "
+ "lbits: %2u tree: %2u length: %4u",
+ (ulong) (count - huff_counts + 1),
+ count->field_type,
+ count->pack_type, count->max_zero_fill,
+ count->length_bits, count->tree->tree_number,
+ count->field_length));
+
+ /* Check if the column contains spaces only. */
if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
{
for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
if (pos == end_pos)
{
+ DBUG_PRINT("fields",
+ ("PACK_TYPE_SPACE_FIELDS spaces only, bits: 1"));
+ DBUG_PRINT("fields", ("---"));
write_bits(1,1);
start_pos=end_pos;
continue;
}
+ DBUG_PRINT("fields",
+ ("PACK_TYPE_SPACE_FIELDS not only spaces, bits: 1"));
write_bits(0,1);
}
end_pos-=count->max_zero_fill;
@@ -1740,65 +2507,129 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
case FIELD_SKIP_ZERO:
if (!memcmp((byte*) start_pos,zero_string,field_length))
{
+ DBUG_PRINT("fields", ("FIELD_SKIP_ZERO zeroes only, bits: 1"));
write_bits(1,1);
start_pos=end_pos;
break;
}
+ DBUG_PRINT("fields", ("FIELD_SKIP_ZERO not only zeroes, bits: 1"));
write_bits(0,1);
/* Fall through */
case FIELD_NORMAL:
+ DBUG_PRINT("fields", ("FIELD_NORMAL %lu bytes",
+ (ulong) (end_pos - start_pos)));
for ( ; start_pos < end_pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
+ }
break;
case FIELD_SKIP_ENDSPACE:
for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
- length=(uint) (end_pos-pos);
+ length= (ulong) (end_pos - pos);
if (count->pack_type & PACK_TYPE_SELECTED)
{
if (length > count->min_space)
{
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE more than min_space, bits: 1"));
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
write_bits(1,1);
write_bits(length,count->length_bits);
}
else
{
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE not more than min_space, "
+ "bits: 1"));
write_bits(0,1);
pos=end_pos;
}
}
else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
write_bits(length,count->length_bits);
+ }
+ /* Encode all significant bytes. */
+ DBUG_PRINT("fields", ("FIELD_SKIP_ENDSPACE %lu bytes",
+ (ulong) (pos - start_pos)));
for ( ; start_pos < pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
+ }
start_pos=end_pos;
break;
case FIELD_SKIP_PRESPACE:
for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
- length=(uint) (pos-start_pos);
+ length= (ulong) (pos - start_pos);
if (count->pack_type & PACK_TYPE_SELECTED)
{
if (length > count->min_space)
{
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE more than min_space, bits: 1"));
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
write_bits(1,1);
write_bits(length,count->length_bits);
}
else
{
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE not more than min_space, "
+ "bits: 1"));
pos=start_pos;
write_bits(0,1);
}
}
else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
write_bits(length,count->length_bits);
+ }
+ /* Encode all significant bytes. */
+ DBUG_PRINT("fields", ("FIELD_SKIP_PRESPACE %lu bytes",
+ (ulong) (end_pos - start_pos)));
for (start_pos=pos ; start_pos < end_pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
+ }
break;
case FIELD_CONSTANT:
case FIELD_ZERO:
case FIELD_CHECK:
+ DBUG_PRINT("fields", ("FIELD_CONSTANT/ZERO/CHECK"));
start_pos=end_pos;
break;
case FIELD_INTERVALL:
@@ -1806,6 +2637,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
pos=(byte*) tree_search(&count->int_tree, start_pos,
count->int_tree.custom_arg);
intervall=(uint) (pos - count->tree_buff)/field_length;
+ DBUG_PRINT("fields", ("FIELD_INTERVALL"));
+ DBUG_PRINT("fields", ("index: %4u code: 0x%s bits: %2u",
+ intervall, hexdigits(tree->code[intervall]),
+ (uint) tree->code_len[intervall]));
write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
start_pos=end_pos;
break;
@@ -1814,21 +2649,36 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
ulong blob_length=_mi_calc_blob_length(field_length-
mi_portable_sizeof_char_ptr,
start_pos);
+ /* Empty blobs are encoded with a single 1 bit. */
if (!blob_length)
{
- write_bits(1,1); /* Empty blob */
+ DBUG_PRINT("fields", ("FIELD_BLOB empty, bits: 1"));
+ write_bits(1,1);
}
else
{
byte *blob,*blob_end;
+ DBUG_PRINT("fields", ("FIELD_BLOB not empty, bits: 1"));
write_bits(0,1);
+ /* Write the blob length. */
+ DBUG_PRINT("fields", ("FIELD_BLOB %lu bytes, bits: %2u",
+ blob_length, count->length_bits));
write_bits(blob_length,count->length_bits);
memcpy_fixed(&blob,end_pos-mi_portable_sizeof_char_ptr,
sizeof(char*));
blob_end=blob+blob_length;
+ /* Encode the blob bytes. */
for ( ; blob < blob_end ; blob++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *blob, hexdigits(tree->code[(uchar) *blob]),
+ (uint) tree->code_len[(uchar) *blob],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint)tree->code_len[(uchar) *start_pos])));
write_bits(tree->code[(uchar) *blob],
(uint) tree->code_len[(uchar) *blob]);
+ }
tot_blob_length+=blob_length;
}
start_pos= end_pos;
@@ -1839,18 +2689,34 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
ulong col_length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
uint2korr(start_pos));
+ /* Empty varchar are encoded with a single 1 bit. */
if (!col_length)
{
+ DBUG_PRINT("fields", ("FIELD_VARCHAR empty, bits: 1"));
write_bits(1,1); /* Empty varchar */
}
else
{
byte *end=start_pos+pack_length+col_length;
+ DBUG_PRINT("fields", ("FIELD_VARCHAR not empty, bits: 1"));
write_bits(0,1);
+ /* Write the varchar length. */
+ DBUG_PRINT("fields", ("FIELD_VARCHAR %lu bytes, bits: %2u",
+ col_length, count->length_bits));
write_bits(col_length,count->length_bits);
+ /* Encode the varchar bytes. */
for (start_pos+=pack_length ; start_pos < end ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint)tree->code_len[(uchar) *start_pos])));
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
+ }
}
start_pos= end_pos;
break;
@@ -1859,12 +2725,17 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
abort(); /* Impossible */
}
start_pos+=count->max_zero_fill;
+ DBUG_PRINT("fields", ("---"));
}
flush_bits();
- length=(ulong) (file_buffer.pos-record_pos)-max_pack_length;
+ length=(ulong) ((byte*) file_buffer.pos - record_pos) - max_pack_length;
pack_length=save_pack_length(record_pos,length);
if (pack_blob_length)
pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length);
+ DBUG_PRINT("fields", ("record: %lu length: %lu blob-length: %lu "
+ "length-bytes: %lu", (ulong) record_count, length,
+ tot_blob_length, pack_length));
+ DBUG_PRINT("fields", ("==="));
/* Correct file buffer if the header was smaller */
if (pack_length != max_pack_length)
@@ -1876,9 +2747,11 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
min_record_length=(uint) length;
if (length > (ulong) max_record_length)
max_record_length=(uint) length;
- if (write_loop && ++record_count % WRITE_COUNT == 0)
+ record_count++;
+ if (write_loop && record_count % WRITE_COUNT == 0)
{
- printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ VOID(printf("%lu\r", (ulong) record_count));
+ VOID(fflush(stdout));
}
}
else if (error != HA_ERR_RECORD_DELETED)
@@ -1888,8 +2761,11 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
error=0;
else
{
- fprintf(stderr,"%s: Got error %d reading records\n",my_progname,error);
+ VOID(fprintf(stderr, "%s: Got error %d reading records\n",
+ my_progname, error));
}
+ if (verbose >= 2)
+ VOID(printf("wrote %s records.\n", llstr((longlong) record_count, llbuf)));
my_afree((gptr) record);
mrg->ref_length=max_pack_length;
@@ -1929,7 +2805,7 @@ static void init_file_buffer(File file, pbool read_buffer)
file_buffer.pos=file_buffer.buffer;
file_buffer.bits=BITS_SAVED;
}
- file_buffer.current_byte=0;
+ file_buffer.bitbucket= 0;
}
@@ -1972,7 +2848,8 @@ static int flush_buffer(ulong neaded_length)
tmp=my_realloc(file_buffer.buffer, neaded_length,MYF(MY_WME));
if (!tmp)
return 1;
- file_buffer.pos= tmp + (ulong) (file_buffer.pos - file_buffer.buffer);
+ file_buffer.pos= ((uchar*) tmp +
+ (ulong) (file_buffer.pos - file_buffer.buffer));
file_buffer.buffer=tmp;
file_buffer.end=tmp+neaded_length-8;
}
@@ -1987,68 +2864,59 @@ static void end_file_buffer(void)
/* output `bits` low bits of `value' */
-static void write_bits (register ulong value, register uint bits)
+static void write_bits(register ulonglong value, register uint bits)
{
- if ((file_buffer.bits-=(int) bits) >= 0)
+ DBUG_ASSERT(((bits < 8 * sizeof(value)) && ! (value >> bits)) ||
+ (bits == 8 * sizeof(value)));
+
+ if ((file_buffer.bits-= (int) bits) >= 0)
{
- file_buffer.current_byte|=value << file_buffer.bits;
+ file_buffer.bitbucket|= value << file_buffer.bits;
}
else
{
- reg3 uint byte_buff;
+ reg3 ulonglong bit_buffer;
bits= (uint) -file_buffer.bits;
- DBUG_ASSERT(bits <= 8 * sizeof(value));
- byte_buff= (file_buffer.current_byte |
- ((bits != 8 * sizeof(value)) ? (uint) (value >> bits) : 0));
-#if BITS_SAVED == 32
- *file_buffer.pos++= (byte) (byte_buff >> 24) ;
- *file_buffer.pos++= (byte) (byte_buff >> 16) ;
+ bit_buffer= (file_buffer.bitbucket |
+ ((bits != 8 * sizeof(value)) ? (value >> bits) : 0));
+#if BITS_SAVED == 64
+ *file_buffer.pos++= (uchar) (bit_buffer >> 56);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 48);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 40);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 32);
#endif
- *file_buffer.pos++= (byte) (byte_buff >> 8) ;
- *file_buffer.pos++= (byte) byte_buff;
+ *file_buffer.pos++= (uchar) (bit_buffer >> 24);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 16);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 8);
+ *file_buffer.pos++= (uchar) (bit_buffer);
- DBUG_ASSERT(bits <= 8 * sizeof(ulong));
if (bits != 8 * sizeof(value))
- value&= (((ulong) 1) << bits) - 1;
-#if BITS_SAVED == 16
- if (bits >= sizeof(uint))
- {
- bits-=8;
- *file_buffer.pos++= (uchar) (value >> bits);
- value&= (1 << bits)-1;
- if (bits >= sizeof(uint))
- {
- bits-=8;
- *file_buffer.pos++= (uchar) (value >> bits);
- value&= (1 << bits)-1;
- }
- }
-#endif
+ value&= (((ulonglong) 1) << bits) - 1;
if (file_buffer.pos >= file_buffer.end)
VOID(flush_buffer(~ (ulong) 0));
file_buffer.bits=(int) (BITS_SAVED - bits);
- file_buffer.current_byte=(uint) (value << (BITS_SAVED - bits));
+ file_buffer.bitbucket= value << (BITS_SAVED - bits);
}
return;
}
/* Flush bits in bit_buffer to buffer */
-static void flush_bits (void)
+static void flush_bits(void)
{
- uint bits,byte_buff;
+ int bits;
+ ulonglong bit_buffer;
- bits=(file_buffer.bits) & ~7;
- byte_buff = file_buffer.current_byte >> bits;
- bits=BITS_SAVED - bits;
+ bits= file_buffer.bits & ~7;
+ bit_buffer= file_buffer.bitbucket >> bits;
+ bits= BITS_SAVED - bits;
while (bits > 0)
{
- bits-=8;
- *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
+ bits-= 8;
+ *file_buffer.pos++= (uchar) (bit_buffer >> bits);
}
- file_buffer.bits=BITS_SAVED;
- file_buffer.current_byte=0;
- return;
+ file_buffer.bits= BITS_SAVED;
+ file_buffer.bitbucket= 0;
}
@@ -2196,3 +3064,131 @@ static int mrg_close(PACK_MRG_INFO *mrg)
my_free((gptr) mrg->file,MYF(0));
return error;
}
+
+
+#if !defined(DBUG_OFF)
+/*
+ Fake the counts to get big Huffman codes.
+
+ SYNOPSIS
+ fakebigcodes()
+ huff_counts A pointer to the counts array.
+ end_count A pointer past the counts array.
+
+ DESCRIPTION
+
+ Huffman coding works by removing the two least frequent values from
+ the list of values and add a new value with the sum of their
+ incidences in a loop until only one value is left. Every time a
+ value is reused for a new value, it gets one more bit for its
+ encoding. Hence, the least frequent values get the longest codes.
+
+ To get a maximum code length for a value, two of the values must
+ have an incidence of 1. As their sum is 2, the next infrequent value
+ must have at least an incidence of 2, then 4, 8, 16 and so on. This
+ means that one needs 2**n bytes (values) for a code length of n
+ bits. However, using more distinct values forces the use of longer
+ codes, or reaching the code length with less total bytes (values).
+
+ To get 64(32)-bit codes, I sort the counts by decreasing incidence.
+ I assign counts of 1 to the two most frequent values, a count of 2
+ for the next one, then 4, 8, and so on until 2**64-1(2**30-1). All
+ the remaining values get 1. That way every possible byte has an
+ assigned code, though not all codes are used if not all byte values
+ are present in the column.
+
+ This strategy would work with distinct column values too, but
+ requires that at least 64(32) values are present. To make things
+ easier here, I cancel all distinct column values and force byte
+ compression for all columns.
+
+ RETURN
+ void
+*/
+
+static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count)
+{
+ HUFF_COUNTS *count;
+ my_off_t *cur_count_p;
+ my_off_t *end_count_p;
+ my_off_t **cur_sort_p;
+ my_off_t **end_sort_p;
+ my_off_t *sort_counts[256];
+ my_off_t total;
+ DBUG_ENTER("fakebigcodes");
+
+ for (count= huff_counts; count < end_count; count++)
+ {
+ /*
+ Remove distinct column values.
+ */
+ if (huff_counts->tree_buff)
+ {
+ my_free((gptr) huff_counts->tree_buff, MYF(0));
+ delete_tree(&huff_counts->int_tree);
+ huff_counts->tree_buff= NULL;
+ DBUG_PRINT("fakebigcodes", ("freed distinct column values"));
+ }
+
+ /*
+ Sort counts by decreasing incidence.
+ */
+ cur_count_p= count->counts;
+ end_count_p= cur_count_p + 256;
+ cur_sort_p= sort_counts;
+ while (cur_count_p < end_count_p)
+ *(cur_sort_p++)= cur_count_p++;
+ (void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
+
+ /*
+ Assign faked counts.
+ */
+ cur_sort_p= sort_counts;
+#if SIZEOF_LONG_LONG > 4
+ end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 1;
+#else
+ end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 2;
+#endif
+ /* Most frequent value gets a faked count of 1. */
+ **(cur_sort_p++)= 1;
+ total= 1;
+ while (cur_sort_p < end_sort_p)
+ {
+ **(cur_sort_p++)= total;
+ total<<= 1;
+ }
+ /* Set the last value. */
+ **(cur_sort_p++)= --total;
+ /*
+ Set the remaining counts.
+ */
+ end_sort_p= sort_counts + 256;
+ while (cur_sort_p < end_sort_p)
+ **(cur_sort_p++)= 1;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Compare two counts for reverse sorting.
+
+ SYNOPSIS
+ fakecmp()
+ count1 One count.
+ count2 Another count.
+
+ RETURN
+ 1 count1 < count2
+ 0 count1 == count2
+ -1 count1 > count2
+*/
+
+static int fakecmp(my_off_t **count1, my_off_t **count2)
+{
+ return ((**count1 < **count2) ? 1 :
+ (**count1 > **count2) ? -1 : 0);
+}
+#endif
+
+
diff --git a/myisammrg/Makefile.am b/myisammrg/Makefile.am
index 6975fab6770..14e3295c1ae 100644
--- a/myisammrg/Makefile.am
+++ b/myisammrg/Makefile.am
@@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
pkglib_LIBRARIES = libmyisammrg.a
noinst_HEADERS = myrg_def.h
libmyisammrg_a_SOURCES = myrg_open.c myrg_extra.c myrg_info.c myrg_locking.c \
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index 3a59a060778..7c7ceb349a4 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -39,7 +39,7 @@ test_DATA = std_data/client-key.pem std_data/client-cert.pem std_data/cacert.pem
std_data/server-cert.pem std_data/server-key.pem
CLEANFILES = $(test_SCRIPTS) $(test_DATA)
-INCLUDES = -I$(srcdir)/../include -I../include -I..
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I..
EXTRA_PROGRAMS = mysql_test_run_new
noinst_HEADERS = my_manage.h
mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c
@@ -48,6 +48,7 @@ mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c
dist-hook:
mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \
$(distdir)/std_data $(distdir)/lib
+ -$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sql $(distdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t
@@ -70,6 +71,7 @@ install-data-local:
$(DESTDIR)$(testdir)/std_data \
$(DESTDIR)$(testdir)/lib
$(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir)
+ -$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sql $(DESTDIR)$(testdir)/t
-$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t
@@ -88,9 +90,16 @@ install-data-local:
$(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib
$(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib
-std_data/%.pem:
+std_data/client-key.pem:
+ @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data
+std_data/client-cert.pem:
+ @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data
+std_data/cacert.pem:
+ @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data
+std_data/server-cert.pem:
+ @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data
+std_data/server-key.pem:
@CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data
-
SUFFIXES = .sh
diff --git a/mysql-test/README b/mysql-test/README
index 65e6186613a..10d64784ed4 100644
--- a/mysql-test/README
+++ b/mysql-test/README
@@ -2,8 +2,17 @@ This directory contains a test suite for mysql daemon. To run
the currently existing test cases, simply execute ./mysql-test-run in
this directory. It will fire up the newly built mysqld and test it.
-If you want to run the test with a running MySQL server use the --external
-option to mysql-test-run.
+If you want to run a test with a running MySQL server use the --extern
+option to mysql-test-run. Please note that in this mode the test suite
+expects user to specify test names to run. Otherwise it falls back to the
+normal "non-extern" behaviour. The reason is that some tests
+could not run with external server. Here is the sample command
+to test "alias" and "analyze" tests on external server:
+
+mysql-test-run --extern alias analyze
+
+To match your setup you might also need to provide --socket, --user and
+other relevant options.
Note that you do not have to have to do make install, and you could
actually have a co-existing MySQL installation - the tests will not
diff --git a/mysql-test/include/not_openssl.inc b/mysql-test/include/not_openssl.inc
new file mode 100644
index 00000000000..afe2ed37c28
--- /dev/null
+++ b/mysql-test/include/not_openssl.inc
@@ -0,0 +1,4 @@
+-- require r/not_openssl.require
+disable_query_log;
+show variables like "have_openssl";
+enable_query_log;
diff --git a/mysql-test/include/ps_create.inc b/mysql-test/include/ps_create.inc
index 306ed3f1cac..b2a6fc4b920 100644
--- a/mysql-test/include/ps_create.inc
+++ b/mysql-test/include/ps_create.inc
@@ -33,7 +33,7 @@ eval create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
- c13 date, c14 datetime, c15 timestamp(14), c16 time,
+ c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql
index 9671de49ca5..77f9b18cb08 100644
--- a/mysql-test/lib/init_db.sql
+++ b/mysql-test/lib/init_db.sql
@@ -128,7 +128,7 @@ CREATE TABLE tables_priv (
Table_name char(64) binary DEFAULT '' NOT NULL,
Grantor char(77) DEFAULT '' NOT NULL,
Timestamp timestamp(14),
- Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
+ Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
PRIMARY KEY (Host,Db,User,Table_name),KEY Grantor (Grantor)
) engine=MyISAM
diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl
index b4f0080a4e9..12714ddc1ad 100644
--- a/mysql-test/lib/mtr_cases.pl
+++ b/mysql-test/lib/mtr_cases.pl
@@ -4,10 +4,11 @@
# and is part of the translation of the Bourne shell script with the
# same name.
+use File::Basename;
use strict;
sub collect_test_cases ($);
-sub collect_one_test_case ($$$$$);
+sub collect_one_test_case ($$$$$$);
##############################################################################
#
@@ -39,23 +40,42 @@ sub collect_test_cases ($) {
if ( @::opt_cases )
{
foreach my $tname ( @::opt_cases ) { # Run in specified order, no sort
+ $tname= basename($tname, ".test");
my $elem= "$tname.test";
if ( ! -f "$testdir/$elem")
{
mtr_error("Test case $tname ($testdir/$elem) is not found");
}
- collect_one_test_case($testdir,$resdir,$tname,$elem,$cases);
+ collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,{});
}
closedir TESTDIR;
}
else
{
+ # ----------------------------------------------------------------------
+ # Skip some tests listed in disabled.def
+ # ----------------------------------------------------------------------
+ my %skiplist;
+ my $skipfile= "$testdir/disabled.def";
+ if ( open(SKIPFILE, $skipfile) )
+ {
+ while ( <SKIPFILE> )
+ {
+ chomp;
+ if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
+ {
+ $skiplist{$1}= $2;
+ }
+ }
+ close SKIPFILE;
+ }
+
foreach my $elem ( sort readdir(TESTDIR) ) {
my $tname= mtr_match_extension($elem,"test");
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);
+ collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%skiplist);
}
closedir TESTDIR;
}
@@ -93,12 +113,13 @@ sub collect_test_cases ($) {
##############################################################################
-sub collect_one_test_case($$$$$) {
+sub collect_one_test_case($$$$$$) {
my $testdir= shift;
my $resdir= shift;
my $tname= shift;
my $elem= shift;
my $cases= shift;
+ my $skiplist=shift;
my $path= "$testdir/$elem";
@@ -126,16 +147,6 @@ sub collect_one_test_case($$$$$) {
return;
}
- # FIXME temporary solution, we have a hard coded list of test cases to
- # skip if we are using the embedded server
-
- if ( $::glob_use_embedded_server and
- mtr_match_any_exact($tname,\@::skip_if_embedded_server) )
- {
- $tinfo->{'skip'}= 1;
- return;
- }
-
# ----------------------------------------------------------------------
# Collect information about test case
# ----------------------------------------------------------------------
@@ -162,6 +173,14 @@ sub collect_one_test_case($$$$$) {
}
}
+ if ( defined mtr_match_prefix($tname,"federated") )
+ {
+ $tinfo->{'slave_num'}= 1; # Default, use one slave
+
+ # FIXME currently we always restart slaves
+ $tinfo->{'slave_restart'}= 1;
+ }
+
# FIXME what about embedded_server + ndbcluster, skip ?!
my $master_opt_file= "$testdir/$tname-master.opt";
@@ -171,52 +190,73 @@ sub collect_one_test_case($$$$$) {
my $slave_sh= "$testdir/$tname-slave.sh";
my $disabled= "$testdir/$tname.disabled";
- $tinfo->{'master_opt'}= ["--default-time-zone=+3:00"];
- $tinfo->{'slave_opt'}= ["--default-time-zone=+3:00"];
+ $tinfo->{'master_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : [];
+ $tinfo->{'slave_opt'}= $::glob_win32 ? ["--default-time-zone=+3:00"] : [];
$tinfo->{'slave_mi'}= [];
if ( -f $master_opt_file )
{
$tinfo->{'master_restart'}= 1; # We think so for now
- # This is a dirty hack from old mysql-test-run, we use the opt file
- # to flag other things as well, it is not a opt list at all
- $tinfo->{'master_opt'}= mtr_get_opts_from_file($master_opt_file);
- foreach my $opt (@{$tinfo->{'master_opt'}})
+ MASTER_OPT:
{
- my $value;
+ my $master_opt= mtr_get_opts_from_file($master_opt_file);
- $value= mtr_match_prefix($opt, "--timezone=");
-
- if ( defined $value )
+ foreach my $opt ( @$master_opt )
{
- $tinfo->{'timezone'}= $value;
- $tinfo->{'master_opt'}= [];
- $tinfo->{'master_restart'}= 0;
- last;
- }
+ my $value;
- $value= mtr_match_prefix($opt, "--result-file=");
+ # This is a dirty hack from old mysql-test-run, we use the opt
+ # file to flag other things as well, it is not a opt list at
+ # all
- if ( defined $value )
- {
- $tinfo->{'result_file'}= "r/$value.result";
- if ( $::opt_result_ext and $::opt_record or
- -f "$tinfo->{'result_file'}$::opt_result_ext")
+ $value= mtr_match_prefix($opt, "--timezone=");
+ if ( defined $value )
+ {
+ $tinfo->{'timezone'}= $value;
+ $tinfo->{'skip'}= 1 if $::glob_win32; # FIXME server unsets TZ
+ last MASTER_OPT;
+ }
+
+ $value= mtr_match_prefix($opt, "--result-file=");
+ if ( defined $value )
{
- $tinfo->{'result_file'}.= $::opt_result_ext;
+ $tinfo->{'result_file'}= "r/$value.result";
+ if ( $::opt_result_ext and $::opt_record or
+ -f "$tinfo->{'result_file'}$::opt_result_ext")
+ {
+ $tinfo->{'result_file'}.= $::opt_result_ext;
+ }
+ $tinfo->{'master_restart'}= 0;
+ last MASTER_OPT;
}
- $tinfo->{'master_opt'}= [];
- $tinfo->{'master_restart'}= 0;
- last;
+
+ # If we set default time zone, remove the one we have
+ $value= mtr_match_prefix($opt, "--default-time-zone=");
+ if ( defined $value )
+ {
+ $tinfo->{'master_opt'}= [];
+ }
+
}
+
+ # Ok, this was a real option list, add it
+ push(@{$tinfo->{'master_opt'}}, @$master_opt);
}
}
if ( -f $slave_opt_file )
{
- $tinfo->{'slave_opt'}= mtr_get_opts_from_file($slave_opt_file);
$tinfo->{'slave_restart'}= 1;
+ my $slave_opt= mtr_get_opts_from_file($slave_opt_file);
+
+ foreach my $opt ( @$slave_opt )
+ {
+ # If we set default time zone, remove the one we have
+ my $value= mtr_match_prefix($opt, "--default-time-zone=");
+ $tinfo->{'slave_opt'}= [] if defined $value;
+ }
+ push(@{$tinfo->{'slave_opt'}}, @$slave_opt);
}
if ( -f $slave_mi_file )
@@ -251,6 +291,14 @@ sub collect_one_test_case($$$$$) {
}
}
+ # FIXME why this late?
+ if ( $skiplist->{$tname} )
+ {
+ $tinfo->{'skip'}= 1;
+ $tinfo->{'disable'}= 1; # Sub type of 'skip'
+ $tinfo->{'comment'}= $skiplist->{$tname} if $skiplist->{$tname};
+ }
+
if ( -f $disabled )
{
$tinfo->{'skip'}= 1;
diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl
index efa1b3bec21..c1aab340a16 100644
--- a/mysql-test/lib/mtr_misc.pl
+++ b/mysql-test/lib/mtr_misc.pl
@@ -9,6 +9,9 @@ use strict;
sub mtr_full_hostname ();
sub mtr_init_args ($);
sub mtr_add_arg ($$);
+sub mtr_path_exists(@);
+sub mtr_script_exists(@);
+sub mtr_exe_exists(@);
##############################################################################
#
@@ -47,4 +50,54 @@ sub mtr_add_arg ($$) {
push(@$args, sprintf($format, @fargs));
}
+##############################################################################
+
+sub mtr_path_exists (@) {
+ foreach my $path ( @_ )
+ {
+ return $path if -e $path;
+ }
+ if ( @_ == 1 )
+ {
+ mtr_error("Could not find $_[0]");
+ }
+ else
+ {
+ mtr_error("Could not find any of " . join(" ", @_));
+ }
+}
+
+sub mtr_script_exists (@) {
+ foreach my $path ( @_ )
+ {
+ return $path if -x $path;
+ }
+ if ( @_ == 1 )
+ {
+ mtr_error("Could not find $_[0]");
+ }
+ else
+ {
+ mtr_error("Could not find any of " . join(" ", @_));
+ }
+}
+
+sub mtr_exe_exists (@) {
+ my @path= @_;
+ map {$_.= ".exe"} @path if $::glob_win32;
+ foreach my $path ( @path )
+ {
+ return $path if -x $path;
+ }
+ if ( @path == 1 )
+ {
+ mtr_error("Could not find $path[0]");
+ }
+ else
+ {
+ mtr_error("Could not find any of " . join(" ", @path));
+ }
+}
+
+
1;
diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl
index a258d139bb1..0af34d11a3f 100644
--- a/mysql-test/lib/mtr_report.pl
+++ b/mysql-test/lib/mtr_report.pl
@@ -38,6 +38,13 @@ sub mtr_show_failed_diff ($) {
my $result_file= "r/$tname.result";
my $eval_file= "r/$tname.eval";
+ if ( $::opt_suite ne "main" )
+ {
+ $reject_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$reject_file";
+ $result_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$result_file";
+ $eval_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$eval_file";
+ }
+
if ( -f $eval_file )
{
$result_file= $eval_file;
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 5f321757492..0bc32c9eaeb 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -100,31 +100,6 @@ require "lib/mtr_misc.pl";
$Devel::Trace::TRACE= 1;
-my @skip_if_embedded_server=
- (
- "alter_table",
- "bdb-deadlock",
- "connect",
- "flush_block_commit",
- "grant2",
- "grant_cache",
- "grant",
- "init_connect",
- "innodb-deadlock",
- "innodb-lock",
- "mix_innodb_myisam_binlog",
- "mysqlbinlog2",
- "mysqlbinlog",
- "mysqldump",
- "mysql_protocols",
- "ps_1general",
- "rename",
- "show_check",
- "system_mysql_db_fix",
- "user_var",
- "variables",
- );
-
# Used by gcov
our @mysqld_src_dirs=
(
@@ -196,6 +171,7 @@ our $exe_mysqlbinlog;
our $exe_mysql_client_test;
our $exe_mysqld;
our $exe_mysqldump; # Called from test case
+our $exe_mysqlshow; # Called from test case
our $exe_mysql_fix_system_tables;
our $exe_mysqltest;
our $exe_slave_mysqld;
@@ -241,6 +217,7 @@ our $opt_ndbcluster_port;
our $opt_ndbconnectstring;
our $opt_no_manager; # Does nothing now, we never use manager
+our $opt_manager_port; # Does nothing now, we never use manager
our $opt_old_master;
@@ -287,6 +264,7 @@ our $opt_warnings;
our $opt_udiff;
+our $opt_skip_ndbcluster;
our $opt_with_ndbcluster;
our $opt_with_openssl;
@@ -309,6 +287,7 @@ sub executable_setup ();
sub environment_setup ();
sub kill_running_server ();
sub kill_and_cleanup ();
+sub ndbcluster_support ();
sub ndbcluster_install ();
sub ndbcluster_start ();
sub ndbcluster_stop ();
@@ -325,7 +304,7 @@ sub mysqld_arguments ($$$$$);
sub stop_masters_slaves ();
sub stop_masters ();
sub stop_slaves ();
-sub run_mysqltest ($$);
+sub run_mysqltest ($);
sub usage ($);
######################################################################
@@ -341,6 +320,12 @@ sub main () {
initial_setup();
command_line_setup();
executable_setup();
+
+ if (! $opt_skip_ndbcluster and ! $opt_with_ndbcluster)
+ {
+ $opt_with_ndbcluster= ndbcluster_support();
+ }
+
environment_setup();
signal_setup();
@@ -441,7 +426,8 @@ sub initial_setup () {
{
# Windows programs like 'mysqld' needs Windows paths
$glob_mysql_test_dir= `cygpath -m $glob_mysql_test_dir`;
- $glob_cygwin_shell= `cygpath -w $ENV{'SHELL'}`; # The Windows path c:\...
+ my $shell= $ENV{'SHELL'} || "/bin/bash";
+ $glob_cygwin_shell= `cygpath -w $shell`; # The Windows path c:\...
chomp($glob_mysql_test_dir);
chomp($glob_cygwin_shell);
}
@@ -468,9 +454,9 @@ sub command_line_setup () {
# These are defaults for things that are set on the command line
$opt_suite= "main"; # Special default suite
- my $opt_master_myport= 9306;
- my $opt_slave_myport= 9308;
- $opt_ndbcluster_port= 9350;
+ my $opt_master_myport= 9306;
+ my $opt_slave_myport= 9308;
+ $opt_ndbcluster_port= 9350;
# Read the command line
# Note: Keep list, and the order, in sync with usage at end of this file
@@ -481,11 +467,12 @@ sub command_line_setup () {
'ps-protocol' => \$opt_ps_protocol,
'bench' => \$opt_bench,
'small-bench' => \$opt_small_bench,
- 'no-manager' => \$opt_no_manager,
+ 'no-manager' => \$opt_no_manager, # Currently not used
# Control what test suites or cases to run
'force' => \$opt_force,
'with-ndbcluster' => \$opt_with_ndbcluster,
+ 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
'do-test=s' => \$opt_do_test,
'suite=s' => \$opt_suite,
'skip-rpl' => \$opt_skip_rpl,
@@ -495,6 +482,7 @@ sub command_line_setup () {
'master_port=i' => \$opt_master_myport,
'slave_port=i' => \$opt_slave_myport,
'ndbcluster_port=i' => \$opt_ndbcluster_port,
+ 'manager-port=i' => \$opt_manager_port, # Currently not used
# Test case authoring
'record' => \$opt_record,
@@ -684,6 +672,11 @@ sub command_line_setup () {
$opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port";
}
+ if ( $opt_skip_ndbcluster )
+ {
+ $opt_with_ndbcluster= 0;
+ }
+
# FIXME
#if ( $opt_valgrind or $opt_valgrind_all )
@@ -785,137 +778,89 @@ sub executable_setup () {
if ( $opt_source_dist )
{
- if ( $glob_use_embedded_server )
- {
- if ( -f "$glob_basedir/libmysqld/examples/mysqltest" )
- {
- $exe_mysqltest= "$glob_basedir/libmysqld/examples/mysqltest";
- }
- else
- {
- mtr_error("Can't find embedded server 'mysqltest'");
- }
- $exe_mysql_client_test=
- "$glob_basedir/libmysqld/examples/mysql_client_test_embedded";
- }
- else
- {
- if ( -f "$glob_basedir/client/.libs/lt-mysqltest" )
- {
- $exe_mysqltest= "$glob_basedir/client/.libs/lt-mysqltest";
- }
- elsif ( -f "$glob_basedir/client/.libs/mysqltest" )
- {
- $exe_mysqltest= "$glob_basedir/client/.libs/mysqltest";
- }
- else
- {
- $exe_mysqltest= "$glob_basedir/client/mysqltest";
- }
- $exe_mysql_client_test=
- "$glob_basedir/tests/mysql_client_test";
- }
- if ( -f "$glob_basedir/client/.libs/mysqldump" )
+ if ( $glob_win32 )
{
- $exe_mysqldump= "$glob_basedir/client/.libs/mysqldump";
+ $path_client_bindir= mtr_path_exists("$glob_basedir/client_release",
+ "$glob_basedir/bin");
+ $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-nt");
+ $path_language= mtr_path_exists("$glob_basedir/share/english/");
+ $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets");
}
else
{
- $exe_mysqldump= "$glob_basedir/client/mysqldump";
+ $path_client_bindir= mtr_path_exists("$glob_basedir/client");
+ $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld");
+ $path_language= mtr_path_exists("$glob_basedir/sql/share/english/");
+ $path_charsetsdir= mtr_path_exists("$glob_basedir/sql/share/charsets");
}
- if ( -f "$glob_basedir/client/.libs/mysqlbinlog" )
+
+ if ( $glob_use_embedded_server )
{
- $exe_mysqlbinlog= "$glob_basedir/client/.libs/mysqlbinlog";
+ my $path_examples= "$glob_basedir/libmysqld/examples";
+ $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest");
+ $exe_mysql_client_test=
+ mtr_exe_exists("$path_examples/mysql_client_test_embedded",
+ "/usr/bin/false");
}
else
{
- $exe_mysqlbinlog= "$glob_basedir/client/mysqlbinlog";
+ $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
+ $exe_mysql_client_test=
+ mtr_exe_exists("$glob_basedir/tests/mysql_client_test",
+ "/usr/bin/false");
}
-
- $path_client_bindir= "$glob_basedir/client";
- $exe_mysqld= "$glob_basedir/sql/mysqld";
- $exe_mysqladmin= "$path_client_bindir/mysqladmin";
- $exe_mysql= "$path_client_bindir/mysql";
- $exe_mysql_fix_system_tables= "$glob_basedir/scripts/mysql_fix_privilege_tables";
- $path_language= "$glob_basedir/sql/share/english/";
- $path_charsetsdir= "$glob_basedir/sql/share/charsets";
-
- $path_ndb_tools_dir= "$glob_basedir/ndb/tools";
- $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm";
+ $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump");
+ $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow");
+ $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog");
+ $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin");
+ $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql");
+ $exe_mysql_fix_system_tables=
+ mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables");
+ $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools");
+ $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm";
}
else
{
- my $path_tests_bindir= "$glob_basedir/tests";
-
- $path_client_bindir= "$glob_basedir/bin";
- $exe_mysqltest= "$path_client_bindir/mysqltest";
- $exe_mysqldump= "$path_client_bindir/mysqldump";
- $exe_mysqlbinlog= "$path_client_bindir/mysqlbinlog";
- $exe_mysqladmin= "$path_client_bindir/mysqladmin";
- $exe_mysql= "$path_client_bindir/mysql";
- $exe_mysql_fix_system_tables= "$path_client_bindir/scripts/mysql_fix_privilege_tables";
-
- if ( -d "$glob_basedir/share/mysql/english" )
- {
- $path_language ="$glob_basedir/share/mysql/english/";
- $path_charsetsdir ="$glob_basedir/share/mysql/charsets";
- }
- else
- {
- $path_language ="$glob_basedir/share/english/";
- $path_charsetsdir ="$glob_basedir/share/charsets";
- }
-
- if ( -x "$glob_basedir/libexec/mysqld" )
- {
- $exe_mysqld= "$glob_basedir/libexec/mysqld";
- }
- else
- {
- $exe_mysqld= "$glob_basedir/bin/mysqld";
- }
+ $path_client_bindir= mtr_path_exists("$glob_basedir/bin");
+ $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
+ $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump");
+ $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow");
+ $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog");
+ $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin");
+ $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql");
+ $exe_mysql_fix_system_tables=
+ mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables",
+ "$glob_basedir/scripts/mysql_fix_privilege_tables");
+
+ $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/",
+ "$glob_basedir/share/english/");
+ $path_charsetsdir= mtr_path_exists("$glob_basedir/share/mysql/charsets",
+ "$glob_basedir/share/charsets");
+ $exe_mysqld= mtr_exe_exists ("$glob_basedir/libexec/mysqld",
+ "$glob_basedir/bin/mysqld");
if ( $glob_use_embedded_server )
{
- if ( -f "$path_client_bindir/mysqltest_embedded" )
- {
- # FIXME valgrind?
- $exe_mysqltest="$path_client_bindir/mysqltest_embedded";
- }
- else
- {
- mtr_error("Cannot find embedded server 'mysqltest_embedded'");
- }
- if ( -d "$path_tests_bindir/mysql_client_test_embedded" )
- {
- $exe_mysql_client_test=
- "$path_tests_bindir/mysql_client_test_embedded";
- }
- else
- {
- $exe_mysql_client_test=
- "$path_client_bindir/mysql_client_test_embedded";
- }
+ $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded");
+ $exe_mysql_client_test=
+ mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded",
+ "$path_client_bindir/mysql_client_test_embedded",
+ "/usr/bin/false");
}
else
{
- $exe_mysqltest="$path_client_bindir/mysqltest";
- $exe_mysql_client_test="$path_client_bindir/mysql_client_test";
+ $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
+ $exe_mysql_client_test=
+ mtr_exe_exists("$path_client_bindir/mysql_client_test",
+ "/usr/bin/false"); # FIXME temporary
}
$path_ndb_tools_dir= "$glob_basedir/bin";
$exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm";
}
- if ( ! $exe_master_mysqld )
- {
- $exe_master_mysqld= $exe_mysqld;
- }
-
- if ( ! $exe_slave_mysqld )
- {
- $exe_slave_mysqld= $exe_mysqld;
- }
+ $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld;
+ $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld;
$path_ndb_backup_dir=
"$opt_vardir/ndbcluster-$opt_ndbcluster_port";
@@ -934,15 +879,19 @@ sub executable_setup () {
sub environment_setup () {
# --------------------------------------------------------------------------
- # Set LD_LIBRARY_PATH if we are using shared libraries
+ # We might not use a standard installation directory, like /usr/lib.
+ # Set LD_LIBRARY_PATH to make sure we find our installed libraries.
# --------------------------------------------------------------------------
- $ENV{'LD_LIBRARY_PATH'}=
- "$glob_basedir/lib:$glob_basedir/libmysql/.libs" .
- ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : "");
- $ENV{'DYLD_LIBRARY_PATH'}=
- "$glob_basedir/lib:$glob_basedir/libmysql/.libs" .
- ($ENV{'DYLD_LIBRARY_PATH'} ? ":$ENV{'DYLD_LIBRARY_PATH'}" : "");
+ unless ( $opt_source_dist )
+ {
+ $ENV{'LD_LIBRARY_PATH'}=
+ "$glob_basedir/lib" .
+ ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : "");
+ $ENV{'DYLD_LIBRARY_PATH'}=
+ "$glob_basedir/lib" .
+ ($ENV{'DYLD_LIBRARY_PATH'} ? ":$ENV{'DYLD_LIBRARY_PATH'}" : "");
+ }
# --------------------------------------------------------------------------
# Also command lines in .opt files may contain env vars
@@ -1033,11 +982,6 @@ sub kill_and_cleanup () {
mtr_report("Removing Stale Files");
- if ( -l $opt_vardir and ! unlink($opt_vardir) )
- {
- mtr_error("Can't remove soft link \"$opt_vardir\"");
- }
-
rmtree("$opt_vardir/log");
rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port");
rmtree("$opt_vardir/run");
@@ -1089,6 +1033,23 @@ sub kill_and_cleanup () {
#
##############################################################################
+sub ndbcluster_support () {
+
+ # check ndbcluster support by testing using a switch
+ # that is only available in that case
+ if ( mtr_run($exe_mysqld,
+ ["--no-defaults",
+ "--ndb-use-exact-count",
+ "--help"],
+ "", "/dev/null", "/dev/null", "") != 0 )
+ {
+ mtr_report("No ndbcluster support");
+ return 0;
+ }
+ mtr_report("Has ndbcluster support");
+ return 1;
+}
+
# FIXME why is there a different start below?!
sub ndbcluster_install () {
@@ -1411,10 +1372,11 @@ sub run_testcase ($) {
if ( ! $glob_use_running_server and ! $glob_use_embedded_server )
{
- if ( $tinfo->{'master_restart'} or $master->[0]->{'uses_special_flags'} )
+ if ( $tinfo->{'master_restart'} or
+ $master->[0]->{'running_master_is_special'} )
{
stop_masters();
- $master->[0]->{'uses_special_flags'}= 0; # Forget about why we stopped
+ $master->[0]->{'running_master_is_special'}= 0; # Forget why we stopped
}
# ----------------------------------------------------------------------
@@ -1492,9 +1454,9 @@ sub run_testcase ($) {
}
}
- if ( @{$tinfo->{'master_opt'}} )
+ if ( $tinfo->{'master_restart'} )
{
- $master->[0]->{'uses_special_flags'}= 1;
+ $master->[0]->{'running_master_is_special'}= 1;
}
}
@@ -1541,7 +1503,7 @@ sub run_testcase ($) {
}
unlink($path_timefile);
- my $res= run_mysqltest($tinfo, $tinfo->{'master_opt'});
+ my $res= run_mysqltest($tinfo);
if ( $res == 0 )
{
@@ -1616,17 +1578,18 @@ sub do_before_start_master ($$) {
$tname ne "rpl_crash_binlog_ib_3b")
{
# FIXME we really want separate dir for binlogs
- foreach my $bin ( glob("$opt_vardir/log/master*-bin.*") )
+ foreach my $bin ( glob("$opt_vardir/log/master*-bin*") )
{
unlink($bin);
}
}
+ # FIXME only remove the ones that are tied to this master
# Remove old master.info and relay-log.info files
- unlink("$opt_vardir/master-data/master.info");
- unlink("$opt_vardir/master-data/relay-log.info");
- unlink("$opt_vardir/master1-data/master.info");
- unlink("$opt_vardir/master1-data/relay-log.info");
+ unlink("$master->[0]->{'path_myddir'}/master.info");
+ unlink("$master->[0]->{'path_myddir'}/relay-log.info");
+ unlink("$master->[1]->{'path_myddir'}/master.info");
+ unlink("$master->[1]->{'path_myddir'}/relay-log.info");
# Run master initialization shell script if one exists
if ( $init_script )
@@ -1653,13 +1616,13 @@ sub do_before_start_slave ($$) {
$tname ne "rpl_crash_binlog_ib_3b" )
{
# FIXME we really want separate dir for binlogs
- foreach my $bin ( glob("$opt_vardir/log/slave*-bin.*") )
+ foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") )
{
unlink($bin);
}
# FIXME really master?!
- unlink("$opt_vardir/slave-data/master.info");
- unlink("$opt_vardir/slave-data/relay-log.info");
+ unlink("$slave->[0]->{'path_myddir'}/master.info");
+ unlink("$slave->[0]->{'path_myddir'}/relay-log.info");
}
# Run slave initialization shell script if one exists
@@ -1673,8 +1636,10 @@ sub do_before_start_slave ($$) {
}
}
- `rm -f $opt_vardir/slave-data/log.*`;
-# unlink("$opt_vardir/slave-data/log.*");
+ foreach my $bin ( glob("$slave->[0]->{'path_myddir'}/log.*") )
+ {
+ unlink($bin);
+ }
}
sub mysqld_arguments ($$$$$) {
@@ -1706,6 +1671,7 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir);
mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir);
mtr_add_arg($args, "%s--core", $prefix);
+ mtr_add_arg($args, "%s--log-bin-trust-routine-creators", $prefix);
mtr_add_arg($args, "%s--default-character-set=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
@@ -1720,24 +1686,37 @@ sub mysqld_arguments ($$$$$) {
if ( $type eq 'master' )
{
- mtr_add_arg($args, "%s--log-bin=%s/log/master-bin", $prefix, $opt_vardir);
+ my $id= $idx > 0 ? $idx + 101 : 1;
+
+ mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix,
+ $opt_vardir, $sidx);
mtr_add_arg($args, "%s--pid-file=%s", $prefix,
$master->[$idx]->{'path_mypid'});
mtr_add_arg($args, "%s--port=%d", $prefix,
$master->[$idx]->{'path_myport'});
- mtr_add_arg($args, "%s--server-id=1", $prefix);
+ mtr_add_arg($args, "%s--server-id=%d", $prefix, $id);
mtr_add_arg($args, "%s--socket=%s", $prefix,
$master->[$idx]->{'path_mysock'});
- mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:50M", $prefix);
+ mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:128M:autoextend", $prefix);
mtr_add_arg($args, "%s--local-infile", $prefix);
mtr_add_arg($args, "%s--datadir=%s", $prefix,
$master->[$idx]->{'path_myddir'});
+
+ if ( $idx > 0 )
+ {
+ mtr_add_arg($args, "%s--skip-innodb", $prefix);
+ }
+
+ if ( $opt_skip_ndbcluster )
+ {
+ mtr_add_arg($args, "%s--skip-ndbcluster", $prefix);
+ }
}
if ( $type eq 'slave' )
{
my $slave_server_id= 2 + $idx;
- my $slave_rpl_rank= $idx > 0 ? 2 : $slave_server_id;
+ my $slave_rpl_rank= $slave_server_id;
mtr_add_arg($args, "%s--datadir=%s", $prefix,
$slave->[$idx]->{'path_myddir'});
@@ -1815,6 +1794,7 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix);
mtr_add_arg($args, "%s--sort_buffer=256K", $prefix);
mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix);
+ mtr_add_arg($args, "%s--log-bin-trust-routine-creators", $prefix);
if ( $opt_with_openssl )
{
@@ -1872,19 +1852,11 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix);
mtr_add_arg($args, "%s--init-rpl-role=master", $prefix);
}
- else
+ elsif ( $type eq 'master' )
{
mtr_add_arg($args, "%s--exit-info=256", $prefix);
mtr_add_arg($args, "%s--open-files-limit=1024", $prefix);
-
- if ( $type eq 'master' )
- {
- mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'});
- }
- if ( $type eq 'slave' )
- {
- mtr_add_arg($args, "%s--log=%s", $prefix, $slave->[0]->{'path_mylog'});
- }
+ mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'});
}
return $args;
@@ -2044,9 +2016,8 @@ sub stop_slaves () {
}
-sub run_mysqltest ($$) {
+sub run_mysqltest ($) {
my $tinfo= shift;
- my $master_opts= shift;
my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
"--socket=$master->[0]->{'path_mysock'} --password=";
@@ -2056,8 +2027,16 @@ sub run_mysqltest ($$) {
" --debug=d:t:A,$opt_vardir/log/mysqldump.trace";
}
+ my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " .
+ "--socket=$master->[0]->{'path_mysock'} --password=";
+ if ( $opt_debug )
+ {
+ $cmdline_mysqlshow .=
+ " --debug=d:t:A,$opt_vardir/log/mysqlshow.trace";
+ }
+
my $cmdline_mysqlbinlog=
- "$exe_mysqlbinlog --no-defaults --local-load=$opt_tmpdir";
+ "$exe_mysqlbinlog --no-defaults --local-load=$opt_tmpdir --character-sets-dir=$path_charsetsdir";
if ( $opt_debug )
{
@@ -2075,6 +2054,14 @@ sub run_mysqltest ($$) {
"--port=$master->[0]->{'path_myport'} " .
"--socket=$master->[0]->{'path_mysock'}";
+ if ( $glob_use_embedded_server )
+ {
+ $cmdline_mysql_client_test.=
+ " -A --language=$path_language" .
+ " -A --datadir=$slave->[0]->{'path_myddir'}" .
+ " -A --character-sets-dir=$path_charsetsdir";
+ }
+
my $cmdline_mysql_fix_system_tables=
"$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " .
"--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " .
@@ -2088,6 +2075,7 @@ sub run_mysqltest ($$) {
$ENV{'MYSQL'}= $cmdline_mysql;
$ENV{'MYSQL_DUMP'}= $cmdline_mysqldump;
+ $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow;
$ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog;
$ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables;
$ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test;
@@ -2190,8 +2178,7 @@ sub run_mysqltest ($$) {
#
##############################################################################
-sub usage ($)
-{
+sub usage ($) {
print STDERR <<HERE;
mysql-test-run [ OPTIONS ] [ TESTCASE ]
@@ -2220,7 +2207,8 @@ Options that specify ports
master_port=PORT Specify the port number used by the first master
slave_port=PORT Specify the port number used by the first slave
- ndbcluster_port=i Specify the port number used by cluster FIXME
+ ndbcluster_port=PORT Specify the port number used by cluster
+ manager-port=PORT Specify the port number used by manager (currently not used)
Options for test case authoring
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index e3fcfdf2b1e..081fec21563 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -307,7 +307,7 @@ while test $# -gt 0; do
--ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem \
--ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem \
--ssl-key=$MYSQL_TEST_DIR/std_data/server-key.pem"
- MYSQL_TEST_SSL_OPTS="--ssl-ca=$BASEDIR/SSL/cacert.pem \
+ MYSQL_TEST_SSL_OPTS="--ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem \
--ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem \
--ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem" ;;
--no-manager | --skip-manager) USE_MANAGER=0 ;;
@@ -707,6 +707,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc
if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then
MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR"
fi
+# Save path and name of mysqldump
+MYSQL_DUMP_DIR="$MYSQL_DUMP"
+export MYSQL_DUMP_DIR
MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT"
MYSQL_SHOW="$MYSQL_SHOW -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLSHOW_OPT"
MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR --character-sets-dir=$CHARSETSDIR $EXTRA_MYSQLBINLOG_OPT"
diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c
index b8e7f1ba2b7..b23b7ceb6a1 100644
--- a/mysql-test/mysql_test_run_new.c
+++ b/mysql-test/mysql_test_run_new.c
@@ -486,6 +486,7 @@ void start_master()
#endif
add_arg(&al, "--local-infile");
add_arg(&al, "--core");
+ add_arg(&al, "--log-bin-trust-routine-creators");
add_arg(&al, "--datadir=%s", master_dir);
#ifndef __WIN__
add_arg(&al, "--pid-file=%s", master_pid);
diff --git a/mysql-test/r/alias.result b/mysql-test/r/alias.result
index 395f49f3635..6f0315da234 100644
--- a/mysql-test/r/alias.result
+++ b/mysql-test/r/alias.result
@@ -27,7 +27,7 @@ hdl_name varchar(30) default NULL,
prov_hdl_nr int(11) NOT NULL default '0',
auto_wirknetz varchar(50) default NULL,
auto_billing varchar(50) default NULL,
-touch timestamp(14) NOT NULL,
+touch timestamp NOT NULL,
kategorie varchar(50) default NULL,
kundentyp varchar(20) NOT NULL default '',
sammel_rech_msisdn varchar(30) NOT NULL default '',
diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result
index 793e50cf653..54780dbbd22 100644
--- a/mysql-test/r/archive.result
+++ b/mysql-test/r/archive.result
@@ -2617,6 +2617,1220 @@ auto fld1 companynr fld3 fld4 fld5 fld6
2 011401 37 breaking dreaded Steinberg W
3 011402 37 Romans scholastics jarring
4 011403 37 intercepted audiology tinily
+INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W');
+INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring','');
+INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
+OPTIMIZE TABLE t2 EXTENDED;
+Table Op Msg_type Msg_text
+test.t2 optimize status OK
+SELECT * FROM t2;
+auto fld1 companynr fld3 fld4 fld5 fld6
+1 000001 00 Omaha teethe neat
+2 011401 37 breaking dreaded Steinberg W
+3 011402 37 Romans scholastics jarring
+4 011403 37 intercepted audiology tinily
+5 011501 37 bewilderingly wallet balled
+6 011701 37 astound parters persist W
+7 011702 37 admonishing eschew attainments
+8 011703 37 sumac quitter fanatic
+9 012001 37 flanking neat measures FAS
+10 012003 37 combed Steinberg rightfulness
+11 012004 37 subjective jarring capably
+12 012005 37 scatterbrain tinily impulsive
+13 012301 37 Eulerian balled starlet
+14 012302 36 dubbed persist terminators
+15 012303 37 Kane attainments untying
+16 012304 37 overlay fanatic announces FAS
+17 012305 37 perturb measures featherweight FAS
+18 012306 37 goblins rightfulness pessimist FAS
+19 012501 37 annihilates capably daughter
+20 012602 37 Wotan impulsive decliner FAS
+21 012603 37 snatching starlet lawgiver
+22 012604 37 concludes terminators stated
+23 012605 37 laterally untying readable
+24 012606 37 yelped announces attrition
+25 012701 37 grazing featherweight cascade FAS
+26 012702 37 Baird pessimist motors FAS
+27 012703 37 celery daughter interrogate
+28 012704 37 misunderstander decliner pests W
+29 013601 37 handgun lawgiver stairway
+30 013602 37 foldout stated dopers FAS
+31 013603 37 mystic readable testicle W
+32 013604 37 succumbed attrition Parsifal W
+33 013605 37 Nabisco cascade leavings
+34 013606 37 fingerings motors postulation W
+35 013607 37 aging interrogate squeaking
+36 013608 37 afield pests contrasted
+37 013609 37 ammonium stairway leftover
+38 013610 37 boat dopers whiteners
+39 013801 37 intelligibility testicle erases W
+40 013802 37 Augustine Parsifal Punjab W
+41 013803 37 teethe leavings Merritt
+42 013804 37 dreaded postulation Quixotism
+43 013901 37 scholastics squeaking sweetish FAS
+44 016001 37 audiology contrasted dogging FAS
+45 016201 37 wallet leftover scornfully FAS
+46 016202 37 parters whiteners bellow
+47 016301 37 eschew erases bills
+48 016302 37 quitter Punjab cupboard FAS
+49 016303 37 neat Merritt sureties FAS
+50 016304 37 Steinberg Quixotism puddings
+51 018001 37 jarring sweetish tapestry
+52 018002 37 tinily dogging fetters
+53 018003 37 balled scornfully bivalves
+54 018004 37 persist bellow incurring
+55 018005 37 attainments bills Adolph
+56 018007 37 fanatic cupboard pithed
+57 018008 37 measures sureties emergency
+58 018009 37 rightfulness puddings Miles
+59 018010 37 capably tapestry trimmings
+60 018012 37 impulsive fetters tragedies W
+61 018013 37 starlet bivalves skulking W
+62 018014 37 terminators incurring flint
+63 018015 37 untying Adolph flopping W
+64 018016 37 announces pithed relaxing FAS
+65 018017 37 featherweight emergency offload FAS
+66 018018 37 pessimist Miles suites W
+67 018019 37 daughter trimmings lists FAS
+68 018020 37 decliner tragedies animized FAS
+69 018021 37 lawgiver skulking multilayer W
+70 018022 37 stated flint standardizes FAS
+71 018023 37 readable flopping Judas
+72 018024 37 attrition relaxing vacuuming W
+73 018025 37 cascade offload dentally W
+74 018026 37 motors suites humanness W
+75 018027 37 interrogate lists inch W
+76 018028 37 pests animized Weissmuller W
+77 018029 37 stairway multilayer irresponsibly W
+78 018030 37 dopers standardizes luckily FAS
+79 018032 37 testicle Judas culled W
+80 018033 37 Parsifal vacuuming medical FAS
+81 018034 37 leavings dentally bloodbath FAS
+82 018035 37 postulation humanness subschema W
+83 018036 37 squeaking inch animals W
+84 018037 37 contrasted Weissmuller Micronesia
+85 018038 37 leftover irresponsibly repetitions
+86 018039 37 whiteners luckily Antares
+87 018040 37 erases culled ventilate W
+88 018041 37 Punjab medical pityingly
+89 018042 37 Merritt bloodbath interdependent
+90 018043 37 Quixotism subschema Graves FAS
+91 018044 37 sweetish animals neonatal
+92 018045 37 dogging Micronesia scribbled FAS
+93 018046 37 scornfully repetitions chafe W
+94 018048 37 bellow Antares honoring
+95 018049 37 bills ventilate realtor
+96 018050 37 cupboard pityingly elite
+97 018051 37 sureties interdependent funereal
+98 018052 37 puddings Graves abrogating
+99 018053 50 tapestry neonatal sorters
+100 018054 37 fetters scribbled Conley
+101 018055 37 bivalves chafe lectured
+102 018056 37 incurring honoring Abraham
+103 018057 37 Adolph realtor Hawaii W
+104 018058 37 pithed elite cage
+105 018059 36 emergency funereal hushes
+106 018060 37 Miles abrogating Simla
+107 018061 37 trimmings sorters reporters
+108 018101 37 tragedies Conley Dutchman FAS
+109 018102 37 skulking lectured descendants FAS
+110 018103 37 flint Abraham groupings FAS
+111 018104 37 flopping Hawaii dissociate
+112 018201 37 relaxing cage coexist W
+113 018202 37 offload hushes Beebe
+114 018402 37 suites Simla Taoism
+115 018403 37 lists reporters Connally
+116 018404 37 animized Dutchman fetched FAS
+117 018405 37 multilayer descendants checkpoints FAS
+118 018406 37 standardizes groupings rusting
+119 018409 37 Judas dissociate galling
+120 018601 37 vacuuming coexist obliterates
+121 018602 37 dentally Beebe traitor
+122 018603 37 humanness Taoism resumes FAS
+123 018801 37 inch Connally analyzable FAS
+124 018802 37 Weissmuller fetched terminator FAS
+125 018803 37 irresponsibly checkpoints gritty FAS
+126 018804 37 luckily rusting firearm W
+127 018805 37 culled galling minima
+128 018806 37 medical obliterates Selfridge
+129 018807 37 bloodbath traitor disable
+130 018808 37 subschema resumes witchcraft W
+131 018809 37 animals analyzable betroth W
+132 018810 37 Micronesia terminator Manhattanize
+133 018811 37 repetitions gritty imprint
+134 018812 37 Antares firearm peeked
+135 019101 37 ventilate minima swelling
+136 019102 37 pityingly Selfridge interrelationships W
+137 019103 37 interdependent disable riser
+138 019201 37 Graves witchcraft Gandhian W
+139 030501 37 neonatal betroth peacock A
+140 030502 50 scribbled Manhattanize bee A
+141 030503 37 chafe imprint kanji
+142 030504 37 honoring peeked dental
+143 031901 37 realtor swelling scarf FAS
+144 036001 37 elite interrelationships chasm A
+145 036002 37 funereal riser insolence A
+146 036004 37 abrogating Gandhian syndicate
+147 036005 37 sorters peacock alike
+148 038001 37 Conley bee imperial A
+149 038002 37 lectured kanji convulsion A
+150 038003 37 Abraham dental railway A
+151 038004 37 Hawaii scarf validate A
+152 038005 37 cage chasm normalizes A
+153 038006 37 hushes insolence comprehensive
+154 038007 37 Simla syndicate chewing
+155 038008 37 reporters alike denizen
+156 038009 37 Dutchman imperial schemer
+157 038010 37 descendants convulsion chronicle
+158 038011 37 groupings railway Kline
+159 038012 37 dissociate validate Anatole
+160 038013 37 coexist normalizes partridges
+161 038014 37 Beebe comprehensive brunch
+162 038015 37 Taoism chewing recruited
+163 038016 37 Connally denizen dimensions W
+164 038017 37 fetched schemer Chicana W
+165 038018 37 checkpoints chronicle announced
+166 038101 37 rusting Kline praised FAS
+167 038102 37 galling Anatole employing
+168 038103 37 obliterates partridges linear
+169 038104 37 traitor brunch quagmire
+170 038201 37 resumes recruited western A
+171 038202 37 analyzable dimensions relishing
+172 038203 37 terminator Chicana serving A
+173 038204 37 gritty announced scheduling
+174 038205 37 firearm praised lore
+175 038206 37 minima employing eventful
+176 038208 37 Selfridge linear arteriole A
+177 042801 37 disable quagmire disentangle
+178 042802 37 witchcraft western cured A
+179 046101 37 betroth relishing Fenton W
+180 048001 37 Manhattanize serving avoidable A
+181 048002 37 imprint scheduling drains A
+182 048003 37 peeked lore detectably FAS
+183 048004 37 swelling eventful husky
+184 048005 37 interrelationships arteriole impelling
+185 048006 37 riser disentangle undoes
+186 048007 37 Gandhian cured evened
+187 048008 37 peacock Fenton squeezes
+188 048101 37 bee avoidable destroyer FAS
+189 048102 37 kanji drains rudeness
+190 048201 37 dental detectably beaner FAS
+191 048202 37 scarf husky boorish
+192 048203 37 chasm impelling Everhart
+193 048204 37 insolence undoes encompass A
+194 048205 37 syndicate evened mushrooms
+195 048301 37 alike squeezes Alison A
+196 048302 37 imperial destroyer externally FAS
+197 048303 37 convulsion rudeness pellagra
+198 048304 37 railway beaner cult
+199 048305 37 validate boorish creek A
+200 048401 37 normalizes Everhart Huffman
+201 048402 37 comprehensive encompass Majorca FAS
+202 048403 37 chewing mushrooms governing A
+203 048404 37 denizen Alison gadfly FAS
+204 048405 37 schemer externally reassigned FAS
+205 048406 37 chronicle pellagra intentness W
+206 048407 37 Kline cult craziness
+207 048408 37 Anatole creek psychic
+208 048409 37 partridges Huffman squabbled
+209 048410 37 brunch Majorca burlesque
+210 048411 37 recruited governing capped
+211 048412 37 dimensions gadfly extracted A
+212 048413 37 Chicana reassigned DiMaggio
+213 048601 37 announced intentness exclamation FAS
+214 048602 37 praised craziness subdirectory
+215 048603 37 employing psychic fangs
+216 048604 37 linear squabbled buyer A
+217 048801 37 quagmire burlesque pithing A
+218 050901 37 western capped transistorizing A
+219 051201 37 relishing extracted nonbiodegradable
+220 056002 37 serving DiMaggio dislocate
+221 056003 37 scheduling exclamation monochromatic FAS
+222 056004 37 lore subdirectory batting
+223 056102 37 eventful fangs postcondition A
+224 056203 37 arteriole buyer catalog FAS
+225 056204 37 disentangle pithing Remus
+226 058003 37 cured transistorizing devices A
+227 058004 37 Fenton nonbiodegradable bike A
+228 058005 37 avoidable dislocate qualify
+229 058006 37 drains monochromatic detained
+230 058007 37 detectably batting commended
+231 058101 37 husky postcondition civilize
+232 058102 37 impelling catalog Elmhurst
+233 058103 37 undoes Remus anesthetizing
+234 058105 37 evened devices deaf
+235 058111 37 squeezes bike Brigham
+236 058112 37 destroyer qualify title
+237 058113 37 rudeness detained coarse
+238 058114 37 beaner commended combinations
+239 058115 37 boorish civilize grayness
+240 058116 37 Everhart Elmhurst innumerable FAS
+241 058117 37 encompass anesthetizing Caroline A
+242 058118 37 mushrooms deaf fatty FAS
+243 058119 37 Alison Brigham eastbound
+244 058120 37 externally title inexperienced
+245 058121 37 pellagra coarse hoarder A
+246 058122 37 cult combinations scotch W
+247 058123 37 creek grayness passport A
+248 058124 37 Huffman innumerable strategic FAS
+249 058125 37 Majorca Caroline gated
+250 058126 37 governing fatty flog
+251 058127 37 gadfly eastbound Pipestone
+252 058128 37 reassigned inexperienced Dar
+253 058201 37 intentness hoarder Corcoran
+254 058202 37 craziness scotch flyers A
+255 058303 37 psychic passport competitions W
+256 058304 37 squabbled strategic suppliers FAS
+257 058602 37 burlesque gated skips
+258 058603 37 capped flog institutes
+259 058604 37 extracted Pipestone troop A
+260 058605 37 DiMaggio Dar connective W
+261 058606 37 exclamation Corcoran denies
+262 058607 37 subdirectory flyers polka
+263 060401 36 fangs competitions observations FAS
+264 061701 36 buyer suppliers askers
+265 066201 36 pithing skips homeless FAS
+266 066501 36 transistorizing institutes Anna
+267 068001 36 nonbiodegradable troop subdirectories W
+268 068002 36 dislocate connective decaying FAS
+269 068005 36 monochromatic denies outwitting W
+270 068006 36 batting polka Harpy W
+271 068007 36 postcondition observations crazed
+272 068008 36 catalog askers suffocate
+273 068009 36 Remus homeless provers FAS
+274 068010 36 devices Anna technically
+275 068011 36 bike subdirectories Franklinizations
+276 068202 36 qualify decaying considered
+277 068302 36 detained outwitting tinnily
+278 068303 36 commended Harpy uninterruptedly
+279 068401 36 civilize crazed whistled A
+280 068501 36 Elmhurst suffocate automate
+281 068502 36 anesthetizing provers gutting W
+282 068503 36 deaf technically surreptitious
+283 068602 36 Brigham Franklinizations Choctaw
+284 068603 36 title considered cooks
+285 068701 36 coarse tinnily millivolt FAS
+286 068702 36 combinations uninterruptedly counterpoise
+287 068703 36 grayness whistled Gothicism
+288 076001 36 innumerable automate feminine
+289 076002 36 Caroline gutting metaphysically W
+290 076101 36 fatty surreptitious sanding A
+291 076102 36 eastbound Choctaw contributorily
+292 076103 36 inexperienced cooks receivers FAS
+293 076302 36 hoarder millivolt adjourn
+294 076303 36 scotch counterpoise straggled A
+295 076304 36 passport Gothicism druggists
+296 076305 36 strategic feminine thanking FAS
+297 076306 36 gated metaphysically ostrich
+298 076307 36 flog sanding hopelessness FAS
+299 076402 36 Pipestone contributorily Eurydice
+300 076501 36 Dar receivers excitation W
+301 076502 36 Corcoran adjourn presumes FAS
+302 076701 36 flyers straggled imaginable FAS
+303 078001 36 competitions druggists concoct W
+304 078002 36 suppliers thanking peering W
+305 078003 36 skips ostrich Phelps FAS
+306 078004 36 institutes hopelessness ferociousness FAS
+307 078005 36 troop Eurydice sentences
+308 078006 36 connective excitation unlocks
+309 078007 36 denies presumes engrossing W
+310 078008 36 polka imaginable Ruth
+311 078101 36 observations concoct tying
+312 078103 36 askers peering exclaimers
+313 078104 36 homeless Phelps synergy
+314 078105 36 Anna ferociousness Huey W
+315 082101 36 subdirectories sentences merging
+316 083401 36 decaying unlocks judges A
+317 084001 36 outwitting engrossing Shylock W
+318 084002 36 Harpy Ruth Miltonism
+319 086001 36 crazed tying hen W
+320 086102 36 suffocate exclaimers honeybee FAS
+321 086201 36 provers synergy towers
+322 088001 36 technically Huey dilutes W
+323 088002 36 Franklinizations merging numerals FAS
+324 088003 36 considered judges democracy FAS
+325 088004 36 tinnily Shylock Ibero-
+326 088101 36 uninterruptedly Miltonism invalids
+327 088102 36 whistled hen behavior
+328 088103 36 automate honeybee accruing
+329 088104 36 gutting towers relics A
+330 088105 36 surreptitious dilutes rackets
+331 088106 36 Choctaw numerals Fischbein W
+332 088201 36 cooks democracy phony W
+333 088203 36 millivolt Ibero- cross FAS
+334 088204 36 counterpoise invalids cleanup
+335 088302 37 Gothicism behavior conspirator
+336 088303 37 feminine accruing label FAS
+337 088305 37 metaphysically relics university
+338 088402 37 sanding rackets cleansed FAS
+339 088501 36 contributorily Fischbein ballgown
+340 088502 36 receivers phony starlet
+341 088503 36 adjourn cross aqueous
+342 098001 58 straggled cleanup portrayal A
+343 098002 58 druggists conspirator despising W
+344 098003 58 thanking label distort W
+345 098004 58 ostrich university palmed
+346 098005 58 hopelessness cleansed faced
+347 098006 58 Eurydice ballgown silverware
+348 141903 29 excitation starlet assessor
+349 098008 58 presumes aqueous spiders
+350 098009 58 imaginable portrayal artificially
+351 098010 58 concoct despising reminiscence
+352 098011 58 peering distort Mexican
+353 098012 58 Phelps palmed obnoxious
+354 098013 58 ferociousness faced fragile
+355 098014 58 sentences silverware apprehensible
+356 098015 58 unlocks assessor births
+357 098016 58 engrossing spiders garages
+358 098017 58 Ruth artificially panty
+359 098018 58 tying reminiscence anteater
+360 098019 58 exclaimers Mexican displacement A
+361 098020 58 synergy obnoxious drovers A
+362 098021 58 Huey fragile patenting A
+363 098022 58 merging apprehensible far A
+364 098023 58 judges births shrieks
+365 098024 58 Shylock garages aligning W
+366 098025 37 Miltonism panty pragmatism
+367 106001 36 hen anteater fevers W
+368 108001 36 honeybee displacement reexamines A
+369 108002 36 towers drovers occupancies
+370 108003 36 dilutes patenting sweats FAS
+371 108004 36 numerals far modulators
+372 108005 36 democracy shrieks demand W
+373 108007 36 Ibero- aligning Madeira
+374 108008 36 invalids pragmatism Viennese W
+375 108009 36 behavior fevers chillier W
+376 108010 36 accruing reexamines wildcats FAS
+377 108011 36 relics occupancies gentle
+378 108012 36 rackets sweats Angles W
+379 108101 36 Fischbein modulators accuracies
+380 108102 36 phony demand toggle
+381 108103 36 cross Madeira Mendelssohn W
+382 108111 50 cleanup Viennese behaviorally
+383 108105 36 conspirator chillier Rochford
+384 108106 36 label wildcats mirror W
+385 108107 36 university gentle Modula
+386 108108 50 cleansed Angles clobbering
+387 108109 36 ballgown accuracies chronography
+388 108110 36 starlet toggle Eskimoizeds
+389 108201 36 aqueous Mendelssohn British W
+390 108202 36 portrayal behaviorally pitfalls
+391 108203 36 despising Rochford verify W
+392 108204 36 distort mirror scatter FAS
+393 108205 36 palmed Modula Aztecan
+394 108301 36 faced clobbering acuity W
+395 108302 36 silverware chronography sinking W
+396 112101 36 assessor Eskimoizeds beasts FAS
+397 112102 36 spiders British Witt W
+398 113701 36 artificially pitfalls physicists FAS
+399 116001 36 reminiscence verify folksong A
+400 116201 36 Mexican scatter strokes FAS
+401 116301 36 obnoxious Aztecan crowder
+402 116302 36 fragile acuity merry
+403 116601 36 apprehensible sinking cadenced
+404 116602 36 births beasts alimony A
+405 116603 36 garages Witt principled A
+406 116701 36 panty physicists golfing
+407 116702 36 anteater folksong undiscovered
+408 118001 36 displacement strokes irritates
+409 118002 36 drovers crowder patriots A
+410 118003 36 patenting merry rooms FAS
+411 118004 36 far cadenced towering W
+412 118005 36 shrieks alimony displease
+413 118006 36 aligning principled photosensitive
+414 118007 36 pragmatism golfing inking
+415 118008 36 fevers undiscovered gainers
+416 118101 36 reexamines irritates leaning A
+417 118102 36 occupancies patriots hydrant A
+418 118103 36 sweats rooms preserve
+419 118202 36 modulators towering blinded A
+420 118203 36 demand displease interactions A
+421 118204 36 Madeira photosensitive Barry
+422 118302 36 Viennese inking whiteness A
+423 118304 36 chillier gainers pastimes W
+424 118305 36 wildcats leaning Edenization
+425 118306 36 gentle hydrant Muscat
+426 118307 36 Angles preserve assassinated
+427 123101 36 accuracies blinded labeled
+428 123102 36 toggle interactions glacial A
+429 123301 36 Mendelssohn Barry implied W
+430 126001 36 behaviorally whiteness bibliographies W
+431 126002 36 Rochford pastimes Buchanan
+432 126003 36 mirror Edenization forgivably FAS
+433 126101 36 Modula Muscat innuendo A
+434 126301 36 clobbering assassinated den FAS
+435 126302 36 chronography labeled submarines W
+436 126402 36 Eskimoizeds glacial mouthful A
+437 126601 36 British implied expiring
+438 126602 36 pitfalls bibliographies unfulfilled FAS
+439 126702 36 verify Buchanan precession
+440 128001 36 scatter forgivably nullified
+441 128002 36 Aztecan innuendo affects
+442 128003 36 acuity den Cynthia
+443 128004 36 sinking submarines Chablis A
+444 128005 36 beasts mouthful betterments FAS
+445 128007 36 Witt expiring advertising
+446 128008 36 physicists unfulfilled rubies A
+447 128009 36 folksong precession southwest FAS
+448 128010 36 strokes nullified superstitious A
+449 128011 36 crowder affects tabernacle W
+450 128012 36 merry Cynthia silk A
+451 128013 36 cadenced Chablis handsomest A
+452 128014 36 alimony betterments Persian A
+453 128015 36 principled advertising analog W
+454 128016 36 golfing rubies complex W
+455 128017 36 undiscovered southwest Taoist
+456 128018 36 irritates superstitious suspend
+457 128019 36 patriots tabernacle relegated
+458 128020 36 rooms silk awesome W
+459 128021 36 towering handsomest Bruxelles
+460 128022 36 displease Persian imprecisely A
+461 128023 36 photosensitive analog televise
+462 128101 36 inking complex braking
+463 128102 36 gainers Taoist true FAS
+464 128103 36 leaning suspend disappointing FAS
+465 128104 36 hydrant relegated navally W
+466 128106 36 preserve awesome circus
+467 128107 36 blinded Bruxelles beetles
+468 128108 36 interactions imprecisely trumps
+469 128202 36 Barry televise fourscore W
+470 128203 36 whiteness braking Blackfoots
+471 128301 36 pastimes true Grady
+472 128302 36 Edenization disappointing quiets FAS
+473 128303 36 Muscat navally floundered FAS
+474 128304 36 assassinated circus profundity W
+475 128305 36 labeled beetles Garrisonian W
+476 128307 36 glacial trumps Strauss
+477 128401 36 implied fourscore cemented FAS
+478 128502 36 bibliographies Blackfoots contrition A
+479 128503 36 Buchanan Grady mutations
+480 128504 36 forgivably quiets exhibits W
+481 128505 36 innuendo floundered tits
+482 128601 36 den profundity mate A
+483 128603 36 submarines Garrisonian arches
+484 128604 36 mouthful Strauss Moll
+485 128702 36 expiring cemented ropers
+486 128703 36 unfulfilled contrition bombast
+487 128704 36 precession mutations difficultly A
+488 138001 36 nullified exhibits adsorption
+489 138002 36 affects tits definiteness FAS
+490 138003 36 Cynthia mate cultivation A
+491 138004 36 Chablis arches heals A
+492 138005 36 betterments Moll Heusen W
+493 138006 36 advertising ropers target FAS
+494 138007 36 rubies bombast cited A
+495 138008 36 southwest difficultly congresswoman W
+496 138009 36 superstitious adsorption Katherine
+497 138102 36 tabernacle definiteness titter A
+498 138103 36 silk cultivation aspire A
+499 138104 36 handsomest heals Mardis
+500 138105 36 Persian Heusen Nadia W
+501 138201 36 analog target estimating FAS
+502 138302 36 complex cited stuck A
+503 138303 36 Taoist congresswoman fifteenth A
+504 138304 36 suspend Katherine Colombo
+505 138401 29 relegated titter survey A
+506 140102 29 awesome aspire staffing
+507 140103 29 Bruxelles Mardis obtain
+508 140104 29 imprecisely Nadia loaded
+509 140105 29 televise estimating slaughtered
+510 140201 29 braking stuck lights A
+511 140701 29 true fifteenth circumference
+512 141501 29 disappointing Colombo dull A
+513 141502 29 navally survey weekly A
+514 141901 29 circus staffing wetness
+515 141902 29 beetles obtain visualized
+516 142101 29 trumps loaded Tannenbaum
+517 142102 29 fourscore slaughtered moribund
+518 142103 29 Blackfoots lights demultiplex
+519 142701 29 Grady circumference lockings
+520 143001 29 quiets dull thugs FAS
+521 143501 29 floundered weekly unnerves
+522 143502 29 profundity wetness abut
+523 148001 29 Garrisonian visualized Chippewa A
+524 148002 29 Strauss Tannenbaum stratifications A
+525 148003 29 cemented moribund signaled
+526 148004 29 contrition demultiplex Italianizes A
+527 148005 29 mutations lockings algorithmic A
+528 148006 29 exhibits thugs paranoid FAS
+529 148007 29 tits unnerves camping A
+530 148009 29 mate abut signifying A
+531 148010 29 arches Chippewa Patrice W
+532 148011 29 Moll stratifications search A
+533 148012 29 ropers signaled Angeles A
+534 148013 29 bombast Italianizes semblance
+535 148023 36 difficultly algorithmic taxed
+536 148015 29 adsorption paranoid Beatrice
+537 148016 29 definiteness camping retrace
+538 148017 29 cultivation signifying lockout
+539 148018 29 heals Patrice grammatic
+540 148019 29 Heusen search helmsman
+541 148020 29 target Angeles uniform W
+542 148021 29 cited semblance hamming
+543 148022 29 congresswoman taxed disobedience
+544 148101 29 Katherine Beatrice captivated A
+545 148102 29 titter retrace transferals A
+546 148201 29 aspire lockout cartographer A
+547 148401 29 Mardis grammatic aims FAS
+548 148402 29 Nadia helmsman Pakistani
+549 148501 29 estimating uniform burglarized FAS
+550 148502 29 stuck hamming saucepans A
+551 148503 29 fifteenth disobedience lacerating A
+552 148504 29 Colombo captivated corny
+553 148601 29 survey transferals megabytes FAS
+554 148602 29 staffing cartographer chancellor
+555 150701 29 obtain aims bulk A
+556 152101 29 loaded Pakistani commits A
+557 152102 29 slaughtered burglarized meson W
+558 155202 36 lights saucepans deputies
+559 155203 29 circumference lacerating northeaster A
+560 155204 29 dull corny dipole
+561 155205 29 weekly megabytes machining 0
+562 156001 29 wetness chancellor therefore
+563 156002 29 visualized bulk Telefunken
+564 156102 29 Tannenbaum commits salvaging
+565 156301 29 moribund meson Corinthianizes A
+566 156302 29 demultiplex deputies restlessly A
+567 156303 29 lockings northeaster bromides
+568 156304 29 thugs dipole generalized A
+569 156305 29 unnerves machining mishaps
+570 156306 29 abut therefore quelling
+571 156501 29 Chippewa Telefunken spiritual A
+572 158001 29 stratifications salvaging beguiles FAS
+573 158002 29 signaled Corinthianizes Trobriand FAS
+574 158101 29 Italianizes restlessly fleeing A
+575 158102 29 algorithmic bromides Armour A
+576 158103 29 paranoid generalized chin A
+577 158201 29 camping mishaps provers A
+578 158202 29 signifying quelling aeronautic A
+579 158203 29 Patrice spiritual voltage W
+580 158204 29 search beguiles sash
+581 158301 29 Angeles Trobriand anaerobic A
+582 158302 29 semblance fleeing simultaneous A
+583 158303 29 taxed Armour accumulating A
+584 158304 29 Beatrice chin Medusan A
+585 158305 29 retrace provers shouted A
+586 158306 29 lockout aeronautic freakish
+587 158501 29 grammatic voltage index FAS
+588 160301 29 helmsman sash commercially
+589 166101 50 uniform anaerobic mistiness A
+590 166102 50 hamming simultaneous endpoint
+591 168001 29 disobedience accumulating straight A
+592 168002 29 captivated Medusan flurried
+593 168003 29 transferals shouted denotative A
+594 168101 29 cartographer freakish coming FAS
+595 168102 29 aims index commencements FAS
+596 168103 29 Pakistani commercially gentleman
+597 168104 29 burglarized mistiness gifted
+598 168202 29 saucepans endpoint Shanghais
+599 168301 29 lacerating straight sportswriting A
+600 168502 29 corny flurried sloping A
+601 168503 29 megabytes denotative navies
+602 168601 29 chancellor coming leaflet A
+603 173001 40 bulk commencements shooter
+604 173701 40 commits gentleman Joplin FAS
+605 173702 40 meson gifted babies
+606 176001 40 deputies Shanghais subdivision FAS
+607 176101 40 northeaster sportswriting burstiness W
+608 176201 40 dipole sloping belted FAS
+609 176401 40 machining navies assails FAS
+610 176501 40 therefore leaflet admiring W
+611 176601 40 Telefunken shooter swaying 0
+612 176602 40 salvaging Joplin Goldstine FAS
+613 176603 40 Corinthianizes babies fitting
+614 178001 40 restlessly subdivision Norwalk W
+615 178002 40 bromides burstiness weakening W
+616 178003 40 generalized belted analogy FAS
+617 178004 40 mishaps assails deludes
+618 178005 40 quelling admiring cokes
+619 178006 40 spiritual swaying Clayton
+620 178007 40 beguiles Goldstine exhausts
+621 178008 40 Trobriand fitting causality
+622 178101 40 fleeing Norwalk sating FAS
+623 178102 40 Armour weakening icon
+624 178103 40 chin analogy throttles
+625 178201 40 provers deludes communicants FAS
+626 178202 40 aeronautic cokes dehydrate FAS
+627 178301 40 voltage Clayton priceless FAS
+628 178302 40 sash exhausts publicly
+629 178401 40 anaerobic causality incidentals FAS
+630 178402 40 simultaneous sating commonplace
+631 178403 40 accumulating icon mumbles
+632 178404 40 Medusan throttles furthermore W
+633 178501 40 shouted communicants cautioned W
+634 186002 37 freakish dehydrate parametrized A
+635 186102 37 index priceless registration A
+636 186201 40 commercially publicly sadly FAS
+637 186202 40 mistiness incidentals positioning
+638 186203 40 endpoint commonplace babysitting
+639 186302 37 straight mumbles eternal A
+640 188007 37 flurried furthermore hoarder
+641 188008 37 denotative cautioned congregates
+642 188009 37 coming parametrized rains
+643 188010 37 commencements registration workers W
+644 188011 37 gentleman sadly sags A
+645 188012 37 gifted positioning unplug W
+646 188013 37 Shanghais babysitting garage A
+647 188014 37 sportswriting eternal boulder A
+648 188015 37 sloping hoarder hollowly A
+649 188016 37 navies congregates specifics
+650 188017 37 leaflet rains Teresa
+651 188102 37 shooter workers Winsett
+652 188103 37 Joplin sags convenient A
+653 188202 37 babies unplug buckboards FAS
+654 188301 40 subdivision garage amenities
+655 188302 40 burstiness boulder resplendent FAS
+656 188303 40 belted hollowly priding FAS
+657 188401 37 assails specifics configurations
+658 188402 37 admiring Teresa untidiness A
+659 188503 37 swaying Winsett Brice W
+660 188504 37 Goldstine convenient sews FAS
+661 188505 37 fitting buckboards participated
+662 190701 37 Norwalk amenities Simon FAS
+663 190703 50 weakening resplendent certificates
+664 191701 37 analogy priding Fitzpatrick
+665 191702 37 deludes configurations Evanston A
+666 191703 37 cokes untidiness misted
+667 196001 37 Clayton Brice textures A
+668 196002 37 exhausts sews save
+669 196003 37 causality participated count
+670 196101 37 sating Simon rightful A
+671 196103 37 icon certificates chaperone
+672 196104 37 throttles Fitzpatrick Lizzy A
+673 196201 37 communicants Evanston clenched A
+674 196202 37 dehydrate misted effortlessly
+675 196203 37 priceless textures accessed
+676 198001 37 publicly save beaters A
+677 198003 37 incidentals count Hornblower FAS
+678 198004 37 commonplace rightful vests A
+679 198005 37 mumbles chaperone indulgences FAS
+680 198006 37 furthermore Lizzy infallibly A
+681 198007 37 cautioned clenched unwilling FAS
+682 198008 37 parametrized effortlessly excrete FAS
+683 198009 37 registration accessed spools A
+684 198010 37 sadly beaters crunches FAS
+685 198011 37 positioning Hornblower overestimating FAS
+686 198012 37 babysitting vests ineffective
+687 198013 37 eternal indulgences humiliation A
+688 198014 37 hoarder infallibly sophomore
+689 198015 37 congregates unwilling star
+690 198017 37 rains excrete rifles
+691 198018 37 workers spools dialysis
+692 198019 37 sags crunches arriving
+693 198020 37 unplug overestimating indulge
+694 198021 37 garage ineffective clockers
+695 198022 37 boulder humiliation languages
+696 198023 50 hollowly sophomore Antarctica A
+697 198024 37 specifics star percentage
+698 198101 37 Teresa rifles ceiling A
+699 198103 37 Winsett dialysis specification
+700 198105 37 convenient arriving regimented A
+701 198106 37 buckboards indulge ciphers
+702 198201 37 amenities clockers pictures A
+703 198204 37 resplendent languages serpents A
+704 198301 53 priding Antarctica allot A
+705 198302 53 configurations percentage realized A
+706 198303 53 untidiness ceiling mayoral A
+707 198304 53 Brice specification opaquely A
+708 198401 37 sews regimented hostess FAS
+709 198402 37 participated ciphers fiftieth
+710 198403 37 Simon pictures incorrectly
+711 202101 37 certificates serpents decomposition FAS
+712 202301 37 Fitzpatrick allot stranglings
+713 202302 37 Evanston realized mixture FAS
+714 202303 37 misted mayoral electroencephalography FAS
+715 202304 37 textures opaquely similarities FAS
+716 202305 37 save hostess charges W
+717 202601 37 count fiftieth freest FAS
+718 202602 37 rightful incorrectly Greenberg FAS
+719 202605 37 chaperone decomposition tinting
+720 202606 37 Lizzy stranglings expelled W
+721 202607 37 clenched mixture warm
+722 202901 37 effortlessly electroencephalography smoothed
+723 202902 37 accessed similarities deductions FAS
+724 202903 37 beaters charges Romano W
+725 202904 37 Hornblower freest bitterroot
+726 202907 37 vests Greenberg corset
+727 202908 37 indulgences tinting securing
+728 203101 37 infallibly expelled environing FAS
+729 203103 37 unwilling warm cute
+730 203104 37 excrete smoothed Crays
+731 203105 37 spools deductions heiress FAS
+732 203401 37 crunches Romano inform FAS
+733 203402 37 overestimating bitterroot avenge
+734 203404 37 ineffective corset universals
+735 203901 37 humiliation securing Kinsey W
+736 203902 37 sophomore environing ravines FAS
+737 203903 37 star cute bestseller
+738 203906 37 rifles Crays equilibrium
+739 203907 37 dialysis heiress extents 0
+740 203908 37 arriving inform relatively
+741 203909 37 indulge avenge pressure FAS
+742 206101 37 clockers universals critiques FAS
+743 206201 37 languages Kinsey befouled
+744 206202 37 Antarctica ravines rightfully FAS
+745 206203 37 percentage bestseller mechanizing FAS
+746 206206 37 ceiling equilibrium Latinizes
+747 206207 37 specification extents timesharing
+748 206208 37 regimented relatively Aden
+749 208001 37 ciphers pressure embassies
+750 208002 37 pictures critiques males FAS
+751 208003 37 serpents befouled shapelessly FAS
+752 208004 37 allot rightfully genres FAS
+753 208008 37 realized mechanizing mastering
+754 208009 37 mayoral Latinizes Newtonian
+755 208010 37 opaquely timesharing finishers FAS
+756 208011 37 hostess Aden abates
+757 208101 37 fiftieth embassies teem
+758 208102 37 incorrectly males kiting FAS
+759 208103 37 decomposition shapelessly stodgy FAS
+760 208104 37 stranglings genres scalps FAS
+761 208105 37 mixture mastering feed FAS
+762 208110 37 electroencephalography Newtonian guitars
+763 208111 37 similarities finishers airships
+764 208112 37 charges abates store
+765 208113 37 freest teem denounces
+766 208201 37 Greenberg kiting Pyle FAS
+767 208203 37 tinting stodgy Saxony
+768 208301 37 expelled scalps serializations FAS
+769 208302 37 warm feed Peruvian FAS
+770 208305 37 smoothed guitars taxonomically FAS
+771 208401 37 deductions airships kingdom A
+772 208402 37 Romano store stint A
+773 208403 37 bitterroot denounces Sault A
+774 208404 37 corset Pyle faithful
+775 208501 37 securing Saxony Ganymede FAS
+776 208502 37 environing serializations tidiness FAS
+777 208503 37 cute Peruvian gainful FAS
+778 208504 37 Crays taxonomically contrary FAS
+779 208505 37 heiress kingdom Tipperary FAS
+780 210101 37 inform stint tropics W
+781 210102 37 avenge Sault theorizers
+782 210103 37 universals faithful renew 0
+783 210104 37 Kinsey Ganymede already
+784 210105 37 ravines tidiness terminal
+785 210106 37 bestseller gainful Hegelian
+786 210107 37 equilibrium contrary hypothesizer
+787 210401 37 extents Tipperary warningly FAS
+788 213201 37 relatively tropics journalizing FAS
+789 213203 37 pressure theorizers nested
+790 213204 37 critiques renew Lars
+791 213205 37 befouled already saplings
+792 213206 37 rightfully terminal foothill
+793 213207 37 mechanizing Hegelian labeled
+794 216101 37 Latinizes hypothesizer imperiously FAS
+795 216103 37 timesharing warningly reporters FAS
+796 218001 37 Aden journalizing furnishings FAS
+797 218002 37 embassies nested precipitable FAS
+798 218003 37 males Lars discounts FAS
+799 218004 37 shapelessly saplings excises FAS
+800 143503 50 genres foothill Stalin
+801 218006 37 mastering labeled despot FAS
+802 218007 37 Newtonian imperiously ripeness FAS
+803 218008 37 finishers reporters Arabia
+804 218009 37 abates furnishings unruly
+805 218010 37 teem precipitable mournfulness
+806 218011 37 kiting discounts boom FAS
+807 218020 37 stodgy excises slaughter A
+808 218021 50 scalps Stalin Sabine
+809 218022 37 feed despot handy FAS
+810 218023 37 guitars ripeness rural
+811 218024 37 airships Arabia organizer
+812 218101 37 store unruly shipyard FAS
+813 218102 37 denounces mournfulness civics FAS
+814 218103 37 Pyle boom inaccuracy FAS
+815 218201 37 Saxony slaughter rules FAS
+816 218202 37 serializations Sabine juveniles FAS
+817 218203 37 Peruvian handy comprised W
+818 218204 37 taxonomically rural investigations
+819 218205 37 kingdom organizer stabilizes A
+820 218301 37 stint shipyard seminaries FAS
+821 218302 37 Sault civics Hunter A
+822 218401 37 faithful inaccuracy sporty FAS
+823 218402 37 Ganymede rules test FAS
+824 218403 37 tidiness juveniles weasels
+825 218404 37 gainful comprised CERN
+826 218407 37 contrary investigations tempering
+827 218408 37 Tipperary stabilizes afore FAS
+828 218409 37 tropics seminaries Galatean
+829 218410 37 theorizers Hunter techniques W
+830 226001 37 renew sporty error
+831 226002 37 already test veranda
+832 226003 37 terminal weasels severely
+833 226004 37 Hegelian CERN Cassites FAS
+834 226005 37 hypothesizer tempering forthcoming
+835 226006 37 warningly afore guides
+836 226007 37 journalizing Galatean vanish FAS
+837 226008 37 nested techniques lied A
+838 226203 37 Lars error sawtooth FAS
+839 226204 37 saplings veranda fated FAS
+840 226205 37 foothill severely gradually
+841 226206 37 labeled Cassites widens
+842 226207 37 imperiously forthcoming preclude
+843 226208 37 reporters guides Jobrel
+844 226209 37 furnishings vanish hooker
+845 226210 37 precipitable lied rainstorm
+846 226211 37 discounts sawtooth disconnects
+847 228001 37 excises fated cruelty
+848 228004 37 Stalin gradually exponentials A
+849 228005 37 despot widens affective A
+850 228006 37 ripeness preclude arteries
+851 228007 37 Arabia Jobrel Crosby FAS
+852 228008 37 unruly hooker acquaint
+853 228009 37 mournfulness rainstorm evenhandedly
+854 228101 37 boom disconnects percentage
+855 228108 37 slaughter cruelty disobedience
+856 228109 37 Sabine exponentials humility
+857 228110 37 handy affective gleaning A
+858 228111 37 rural arteries petted A
+859 228112 37 organizer Crosby bloater A
+860 228113 37 shipyard acquaint minion A
+861 228114 37 civics evenhandedly marginal A
+862 228115 37 inaccuracy percentage apiary A
+863 228116 37 rules disobedience measures
+864 228117 37 juveniles humility precaution
+865 228118 37 comprised gleaning repelled
+866 228119 37 investigations petted primary FAS
+867 228120 37 stabilizes bloater coverings
+868 228121 37 seminaries minion Artemia A
+869 228122 37 Hunter marginal navigate
+870 228201 37 sporty apiary spatial
+871 228206 37 test measures Gurkha
+872 228207 37 weasels precaution meanwhile A
+873 228208 37 CERN repelled Melinda A
+874 228209 37 tempering primary Butterfield
+875 228210 37 afore coverings Aldrich A
+876 228211 37 Galatean Artemia previewing A
+877 228212 37 techniques navigate glut A
+878 228213 37 error spatial unaffected
+879 228214 37 veranda Gurkha inmate
+880 228301 37 severely meanwhile mineral
+881 228305 37 Cassites Melinda impending A
+882 228306 37 forthcoming Butterfield meditation A
+883 228307 37 guides Aldrich ideas
+884 228308 37 vanish previewing miniaturizes W
+885 228309 37 lied glut lewdly
+886 228310 37 sawtooth unaffected title
+887 228311 37 fated inmate youthfulness
+888 228312 37 gradually mineral creak FAS
+889 228313 37 widens impending Chippewa
+890 228314 37 preclude meditation clamored
+891 228401 65 Jobrel ideas freezes
+892 228402 65 hooker miniaturizes forgivably FAS
+893 228403 65 rainstorm lewdly reduce FAS
+894 228404 65 disconnects title McGovern W
+895 228405 65 cruelty youthfulness Nazis W
+896 228406 65 exponentials creak epistle W
+897 228407 65 affective Chippewa socializes W
+898 228408 65 arteries clamored conceptions
+899 228409 65 Crosby freezes Kevin
+900 228410 65 acquaint forgivably uncovering
+901 230301 37 evenhandedly reduce chews FAS
+902 230302 37 percentage McGovern appendixes FAS
+903 230303 37 disobedience Nazis raining
+904 018062 37 humility epistle infest
+905 230501 37 gleaning socializes compartment
+906 230502 37 petted conceptions minting
+907 230503 37 bloater Kevin ducks
+908 230504 37 minion uncovering roped A
+909 230505 37 marginal chews waltz
+910 230506 37 apiary appendixes Lillian
+911 230507 37 measures raining repressions A
+912 230508 37 precaution infest chillingly
+913 230509 37 repelled compartment noncritical
+914 230901 37 primary minting lithograph
+915 230902 37 coverings ducks spongers
+916 230903 37 Artemia roped parenthood
+917 230904 37 navigate waltz posed
+918 230905 37 spatial Lillian instruments
+919 230906 37 Gurkha repressions filial
+920 230907 37 meanwhile chillingly fixedly
+921 230908 37 Melinda noncritical relives
+922 230909 37 Butterfield lithograph Pandora
+923 230910 37 Aldrich spongers watering A
+924 230911 37 previewing parenthood ungrateful
+925 230912 37 glut posed secures
+926 230913 37 unaffected instruments chastisers
+927 230914 37 inmate filial icon
+928 231304 37 mineral fixedly reuniting A
+929 231305 37 impending relives imagining A
+930 231306 37 meditation Pandora abiding A
+931 231307 37 ideas watering omnisciently
+932 231308 37 miniaturizes ungrateful Britannic
+933 231309 37 lewdly secures scholastics A
+934 231310 37 title chastisers mechanics A
+935 231311 37 youthfulness icon humidly A
+936 231312 37 creak reuniting masterpiece
+937 231313 37 Chippewa imagining however
+938 231314 37 clamored abiding Mendelian
+939 231315 37 freezes omnisciently jarred
+940 232102 37 forgivably Britannic scolds
+941 232103 37 reduce scholastics infatuate
+942 232104 37 McGovern mechanics willed A
+943 232105 37 Nazis humidly joyfully
+944 232106 37 epistle masterpiece Microsoft
+945 232107 37 socializes however fibrosities
+946 232108 37 conceptions Mendelian Baltimorean
+947 232601 37 Kevin jarred equestrian
+948 232602 37 uncovering scolds Goodrich
+949 232603 37 chews infatuate apish A
+950 232605 37 appendixes willed Adlerian
+5950 1232605 37 appendixes willed Adlerian
+5951 1232606 37 appendixes willed Adlerian
+5952 1232607 37 appendixes willed Adlerian
+5953 1232608 37 appendixes willed Adlerian
+5954 1232609 37 appendixes willed Adlerian
+951 232606 37 raining joyfully Tropez
+952 232607 37 infest Microsoft nouns
+953 232608 37 compartment fibrosities distracting
+954 232609 37 minting Baltimorean mutton
+955 236104 37 ducks equestrian bridgeable A
+956 236105 37 roped Goodrich stickers A
+957 236106 37 waltz apish transcontinental A
+958 236107 37 Lillian Adlerian amateurish
+959 236108 37 repressions Tropez Gandhian
+960 236109 37 chillingly nouns stratified
+961 236110 37 noncritical distracting chamberlains
+962 236111 37 lithograph mutton creditably
+963 236112 37 spongers bridgeable philosophic
+964 236113 37 parenthood stickers ores
+965 238005 37 posed transcontinental Carleton
+966 238006 37 instruments amateurish tape A
+967 238007 37 filial Gandhian afloat A
+968 238008 37 fixedly stratified goodness A
+969 238009 37 relives chamberlains welcoming
+970 238010 37 Pandora creditably Pinsky FAS
+971 238011 37 watering philosophic halting
+972 238012 37 ungrateful ores bibliography
+973 238013 37 secures Carleton decoding
+974 240401 41 chastisers tape variance A
+975 240402 41 icon afloat allowed A
+976 240901 41 reuniting goodness dire A
+977 240902 41 imagining welcoming dub A
+978 241801 41 abiding Pinsky poisoning
+979 242101 41 omnisciently halting Iraqis A
+980 242102 41 Britannic bibliography heaving
+981 242201 41 scholastics decoding population A
+982 242202 41 mechanics variance bomb A
+983 242501 41 humidly allowed Majorca A
+984 242502 41 masterpiece dire Gershwins
+985 246201 41 however dub explorers
+986 246202 41 Mendelian poisoning libretto A
+987 246203 41 jarred Iraqis occurred
+988 246204 41 scolds heaving Lagos
+989 246205 41 infatuate population rats
+990 246301 41 willed bomb bankruptcies A
+991 246302 41 joyfully Majorca crying
+992 248001 41 Microsoft Gershwins unexpected
+993 248002 41 fibrosities explorers accessed A
+994 248003 41 Baltimorean libretto colorful A
+995 248004 41 equestrian occurred versatility A
+996 248005 41 Goodrich Lagos cosy
+997 248006 41 apish rats Darius A
+998 248007 41 Adlerian bankruptcies mastering A
+999 248008 41 Tropez crying Asiaticizations A
+1000 248009 41 nouns unexpected offerers A
+1001 248010 41 distracting accessed uncles A
+1002 248011 41 mutton colorful sleepwalk
+1003 248012 41 bridgeable versatility Ernestine
+1004 248013 41 stickers cosy checksumming
+1005 248014 41 transcontinental Darius stopped
+1006 248015 41 amateurish mastering sicker
+1007 248016 41 Gandhian Asiaticizations Italianization
+1008 248017 41 stratified offerers alphabetic
+1009 248018 41 chamberlains uncles pharmaceutic
+1010 248019 41 creditably sleepwalk creator
+1011 248020 41 philosophic Ernestine chess
+1012 248021 41 ores checksumming charcoal
+1013 248101 41 Carleton stopped Epiphany A
+1014 248102 41 tape sicker bulldozes A
+1015 248201 41 afloat Italianization Pygmalion A
+1016 248202 41 goodness alphabetic caressing A
+1017 248203 41 welcoming pharmaceutic Palestine A
+1018 248204 41 Pinsky creator regimented A
+1019 248205 41 halting chess scars A
+1020 248206 41 bibliography charcoal realest A
+1021 248207 41 decoding Epiphany diffusing A
+1022 248208 41 variance bulldozes clubroom A
+1023 248209 41 allowed Pygmalion Blythe A
+1024 248210 41 dire caressing ahead
+1025 248211 50 dub Palestine reviver
+1026 250501 34 poisoning regimented retransmitting A
+1027 250502 34 Iraqis scars landslide
+1028 250503 34 heaving realest Eiffel
+1029 250504 34 population diffusing absentee
+1030 250505 34 bomb clubroom aye
+1031 250601 34 Majorca Blythe forked A
+1032 250602 34 Gershwins ahead Peruvianizes
+1033 250603 34 explorers reviver clerked
+1034 250604 34 libretto retransmitting tutor
+1035 250605 34 occurred landslide boulevard
+1036 251001 34 Lagos Eiffel shuttered
+1037 251002 34 rats absentee quotes A
+1038 251003 34 bankruptcies aye Caltech
+1039 251004 34 crying forked Mossberg
+1040 251005 34 unexpected Peruvianizes kept
+1041 251301 34 accessed clerked roundly
+1042 251302 34 colorful tutor features A
+1043 251303 34 versatility boulevard imaginable A
+1044 251304 34 cosy shuttered controller
+1045 251305 34 Darius quotes racial
+1046 251401 34 mastering Caltech uprisings A
+1047 251402 34 Asiaticizations Mossberg narrowed A
+1048 251403 34 offerers kept cannot A
+1049 251404 34 uncles roundly vest
+1050 251405 34 sleepwalk features famine
+1051 251406 34 Ernestine imaginable sugars
+1052 251801 34 checksumming controller exterminated A
+1053 251802 34 stopped racial belays
+1054 252101 34 sicker uprisings Hodges A
+1055 252102 34 Italianization narrowed translatable
+1056 252301 34 alphabetic cannot duality A
+1057 252302 34 pharmaceutic vest recording A
+1058 252303 34 creator famine rouses A
+1059 252304 34 chess sugars poison
+1060 252305 34 charcoal exterminated attitude
+1061 252306 34 Epiphany belays dusted
+1062 252307 34 bulldozes Hodges encompasses
+1063 252308 34 Pygmalion translatable presentation
+1064 252309 34 caressing duality Kantian
+1065 256001 34 Palestine recording imprecision A
+1066 256002 34 regimented rouses saving
+1067 256003 34 scars poison maternal
+1068 256004 34 realest attitude hewed
+1069 256005 34 diffusing dusted kerosene
+1070 258001 34 clubroom encompasses Cubans
+1071 258002 34 Blythe presentation photographers
+1072 258003 34 ahead Kantian nymph A
+1073 258004 34 reviver imprecision bedlam A
+1074 258005 34 retransmitting saving north A
+1075 258006 34 landslide maternal Schoenberg A
+1076 258007 34 Eiffel hewed botany A
+1077 258008 34 absentee kerosene curs
+1078 258009 34 aye Cubans solidification
+1079 258010 34 forked photographers inheritresses
+1080 258011 34 Peruvianizes nymph stiller
+1081 258101 68 clerked bedlam t1 A
+1082 258102 68 tutor north suite A
+1083 258103 34 boulevard Schoenberg ransomer
+1084 258104 68 shuttered botany Willy
+1085 258105 68 quotes curs Rena A
+1086 258106 68 Caltech solidification Seattle A
+1087 258107 68 Mossberg inheritresses relaxes A
+1088 258108 68 kept stiller exclaim
+1089 258109 68 roundly t1 implicated A
+1090 258110 68 features suite distinguish
+1091 258111 68 imaginable ransomer assayed
+1092 258112 68 controller Willy homeowner
+1093 258113 68 racial Rena and
+1094 258201 34 uprisings Seattle stealth
+1095 258202 34 narrowed relaxes coinciding A
+1096 258203 34 cannot exclaim founder A
+1097 258204 34 vest implicated environing
+1098 258205 34 famine distinguish jewelry
+1099 258301 34 sugars assayed lemons A
+1100 258401 34 exterminated homeowner brokenness A
+1101 258402 34 belays and bedpost A
+1102 258403 34 Hodges stealth assurers A
+1103 258404 34 translatable coinciding annoyers
+1104 258405 34 duality founder affixed
+1105 258406 34 recording environing warbling
+1106 258407 34 rouses jewelry seriously
+1107 228123 37 poison lemons boasted
+1108 250606 34 attitude brokenness Chantilly
+1109 208405 37 dusted bedpost Iranizes
+1110 212101 37 encompasses assurers violinist
+1111 218206 37 presentation annoyers extramarital
+1112 150401 37 Kantian affixed spates
+1113 248212 41 imprecision warbling cloakroom
+1114 128026 00 saving seriously gazer
+1115 128024 00 maternal boasted hand
+1116 128027 00 hewed Chantilly tucked
+1117 128025 00 kerosene Iranizes gems
+1118 128109 00 Cubans violinist clinker
+1119 128705 00 photographers extramarital refiner
+1120 126303 00 nymph spates callus
+1121 128308 00 bedlam cloakroom leopards
+1122 128204 00 north gazer comfortingly
+1123 128205 00 Schoenberg hand generically
+1124 128206 00 botany tucked getters
+1125 128207 00 curs gems sexually
+1126 118205 00 solidification clinker spear
+1127 116801 00 inheritresses refiner serums
+1128 116803 00 stiller callus Italianization
+1129 116804 00 t1 leopards attendants
+1130 116802 00 suite comfortingly spies
+1131 128605 00 ransomer generically Anthony
+1132 118308 00 Willy getters planar
+1133 113702 00 Rena sexually cupped
+1134 113703 00 Seattle spear cleanser
+1135 112103 00 relaxes serums commuters
+1136 118009 00 exclaim Italianization honeysuckle
+5136 1118009 00 exclaim Italianization honeysuckle
+1137 138011 00 implicated attendants orphanage
+1138 138010 00 distinguish spies skies
+1139 138012 00 assayed Anthony crushers
+1140 068304 00 homeowner planar Puritan
+1141 078009 00 and cupped squeezer
+1142 108013 00 stealth cleanser bruises
+1143 084004 00 coinciding commuters bonfire
+1144 083402 00 founder honeysuckle Colombo
+1145 084003 00 environing orphanage nondecreasing
+1146 088504 00 jewelry skies innocents
+1147 088005 00 lemons crushers masked
+1148 088007 00 brokenness Puritan file
+1149 088006 00 bedpost squeezer brush
+1150 148025 00 assurers bruises mutilate
+1151 148024 00 annoyers bonfire mommy
+1152 138305 00 affixed Colombo bulkheads
+1153 138306 00 warbling nondecreasing undeclared
+1154 152701 00 seriously innocents displacements
+1155 148505 00 boasted masked nieces
+1156 158003 00 Chantilly file coeducation
+1157 156201 00 Iranizes brush brassy
+1158 156202 00 violinist mutilate authenticator
+1159 158307 00 extramarital mommy Washoe
+1160 158402 00 spates bulkheads penny
+1161 158401 00 cloakroom undeclared Flagler
+1162 068013 00 gazer displacements stoned
+1163 068012 00 hand nieces cranes
+1164 068203 00 tucked coeducation masterful
+1165 088205 00 gems brassy biracial
+1166 068704 00 clinker authenticator steamships
+1167 068604 00 refiner Washoe windmills
+1168 158502 00 callus penny exploit
+1169 123103 00 leopards Flagler riverfront
+1170 148026 00 comfortingly stoned sisterly
+1171 123302 00 generically cranes sharpshoot
+1172 076503 00 getters masterful mittens
+1173 126304 00 sexually biracial interdependency
+1174 068306 00 spear steamships policy
+1175 143504 00 serums windmills unleashing
+1176 160201 00 Italianization exploit pretenders
+1177 148028 00 attendants riverfront overstatements
+1178 148027 00 spies sisterly birthed
+1179 143505 00 Anthony sharpshoot opportunism
+1180 108014 00 planar mittens showroom
+1181 076104 00 cupped interdependency compromisingly
+1182 078106 00 cleanser policy Medicare
+1183 126102 00 commuters unleashing corresponds
+1184 128029 00 honeysuckle pretenders hardware
+1185 128028 00 orphanage overstatements implant
+1186 018410 00 skies birthed Alicia
+1187 128110 00 crushers opportunism requesting
+1188 148506 00 Puritan showroom produced
+1189 123303 00 squeezer compromisingly criticizes
+1190 123304 00 bruises Medicare backer
+1191 068504 00 bonfire corresponds positively
+1192 068305 00 Colombo hardware colicky
+1193 000000 00 nondecreasing implant thrillingly
+1 000001 00 Omaha teethe neat
+2 011401 37 breaking dreaded Steinberg W
+3 011402 37 Romans scholastics jarring
+4 011403 37 intercepted audiology tinily
+2 011401 37 breaking dreaded Steinberg W
+3 011402 37 Romans scholastics jarring
+4 011403 37 intercepted audiology tinily
REPAIR TABLE t2;
Table Op Msg_type Msg_text
test.t2 repair status OK
@@ -3825,6 +5039,9 @@ auto fld1 companynr fld3 fld4 fld5 fld6
2 011401 37 breaking dreaded Steinberg W
3 011402 37 Romans scholastics jarring
4 011403 37 intercepted audiology tinily
+2 011401 37 breaking dreaded Steinberg W
+3 011402 37 Romans scholastics jarring
+4 011403 37 intercepted audiology tinily
INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat','') , (2,011401,37,'breaking','dreaded','Steinberg','W') , (3,011402,37,'Romans','scholastics','jarring','') , (4,011403,37,'intercepted','audiology','tinily','');
SELECT * FROM t2;
auto fld1 companynr fld3 fld4 fld5 fld6
@@ -5031,6 +6248,9 @@ auto fld1 companynr fld3 fld4 fld5 fld6
2 011401 37 breaking dreaded Steinberg W
3 011402 37 Romans scholastics jarring
4 011403 37 intercepted audiology tinily
+2 011401 37 breaking dreaded Steinberg W
+3 011402 37 Romans scholastics jarring
+4 011403 37 intercepted audiology tinily
1 000001 00 Omaha teethe neat
2 011401 37 breaking dreaded Steinberg W
3 011402 37 Romans scholastics jarring
diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result
index a854cf4c7b0..b02f85132aa 100644
--- a/mysql-test/r/case.result
+++ b/mysql-test/r/case.result
@@ -160,6 +160,21 @@ t1 CREATE TABLE `t1` (
`COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
+SELECT 'case+union+test'
+UNION
+SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END;
+case+union+test
+case+union+test
+nobug
+SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END;
+CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END
+nobug
+SELECT 'case+union+test'
+UNION
+SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END;
+case+union+test
+case+union+test
+nobug
CREATE TABLE t1 (EMPNUM INT);
INSERT INTO t1 VALUES (0), (2);
CREATE TABLE t2 (EMPNUM DECIMAL (4, 2));
diff --git a/mysql-test/r/client_xml.result b/mysql-test/r/client_xml.result
index a4164148159..24c05c7f9d6 100644
--- a/mysql-test/r/client_xml.result
+++ b/mysql-test/r/client_xml.result
@@ -15,7 +15,7 @@ insert into t1 values (1, 2, 'a&b a<b a>b');
</row>
</resultset>
<?xml version="1.0"?>
-<mysqldump>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<table_structure name="t1">
<field Field="a&amp;b" Type="int(11)" Null="YES" Key="" Extra="" />
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 338fc429090..4bc2ed0fdc8 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -638,6 +638,17 @@ Warnings:
Warning 1264 Out of range value adjusted for column 'Field1' at row 1
DROP TABLE t1;
SET NAMES latin1;
+CREATE TABLE t1 (
+a varchar(255) NOT NULL default '',
+KEY a (a)
+) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci;
+insert into t1 values (0x803d);
+insert into t1 values (0x005b);
+select hex(a) from t1;
+hex(a)
+005B
+803D
+drop table t1;
CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3));
INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0);
update t1 set b=a;
@@ -646,3 +657,22 @@ a b
1.1 1.100
2.1 2.100
DROP TABLE t1;
+create table t1 (utext varchar(20) character set ucs2);
+insert into t1 values ("lily");
+insert into t1 values ("river");
+prepare stmt from 'select utext from t1 where utext like ?';
+set @param1='%%';
+execute stmt using @param1;
+utext
+lily
+river
+execute stmt using @param1;
+utext
+lily
+river
+select utext from t1 where utext like '%%';
+utext
+lily
+river
+drop table t1;
+deallocate prepare stmt;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 0407a7f388c..66db34bdf83 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -905,6 +905,10 @@ select * from t1 where city = 'Durban ';
id city
2 Durban
drop table t1;
+create table t1 (x set('A', 'B') default 0) character set utf8;
+ERROR 42000: Invalid default value for 'x'
+create table t1 (x enum('A', 'B') default 0) character set utf8;
+ERROR 42000: Invalid default value for 'x'
SET NAMES UTF8;
CREATE TABLE t1 (
`id` int(20) NOT NULL auto_increment,
@@ -939,3 +943,44 @@ content msisdn
ERR Имри.Ðфимим.Ðеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ðд.Д имдимримрад.Ðдимримримрмдиримримримр м.Дадимфшьмримд им.Ðдимимрн имадми 1234567890
11 g 1234567890
DROP TABLE t1,t2;
+create table t1 (a char(20) character set utf8);
+insert into t1 values ('123456'),('андрей');
+alter table t1 modify a char(2) character set utf8;
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+Warning 1265 Data truncated for column 'a' at row 2
+select char_length(a), length(a), a from t1 order by a;
+char_length(a) length(a) a
+2 2 12
+2 4 ан
+drop table t1;
+CREATE TABLE t1 (
+a varchar(255) NOT NULL default '',
+KEY a (a)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
+insert into t1 values (_utf8 0xe880bd);
+insert into t1 values (_utf8 0x5b);
+select hex(a) from t1;
+hex(a)
+5B
+E880BD
+drop table t1;
+CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa');
+SELECT id FROM t1;
+id
+xxx
+aa
+yyy
+aa
+SELECT DISTINCT id FROM t1;
+id
+xxx
+aa
+yyy
+SELECT DISTINCT id FROM t1 ORDER BY id;
+id
+aa
+xxx
+yyy
+DROP TABLE t1;
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index 34d1213d1b2..1a79f6d9736 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -339,7 +339,7 @@ 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
-select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode);
+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;
create table t1 (a text, fulltext key (a));
diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result
index dc51454f1d5..3b52be4b1f2 100644
--- a/mysql-test/r/fulltext_order_by.result
+++ b/mysql-test/r/fulltext_order_by.result
@@ -86,3 +86,77 @@ a rel
1 1
2 2
drop table t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+thread int(11) NOT NULL default '0',
+beitrag longtext NOT NULL,
+PRIMARY KEY (id),
+KEY thread (thread),
+FULLTEXT KEY beitrag (beitrag)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7923 ;
+CREATE TABLE t2 (
+id int(11) NOT NULL auto_increment,
+text varchar(100) NOT NULL default '',
+PRIMARY KEY (id),
+KEY text (text)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ;
+CREATE TABLE t3 (
+id int(11) NOT NULL auto_increment,
+forum int(11) NOT NULL default '0',
+betreff varchar(70) NOT NULL default '',
+PRIMARY KEY (id),
+KEY forum (forum),
+FULLTEXT KEY betreff (betreff)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ;
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+where
+match(b.betreff) against ('+abc' in boolean mode)
+group by a.text, b.id, b.betreff
+union
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+where
+match(c.beitrag) against ('+abc' in boolean mode)
+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
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+where
+match(b.betreff) against ('+abc' in boolean mode)
+union
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+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
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+where
+match(b.betreff) against ('+abc' in boolean mode)
+union
+select a.text, b.id, b.betreff
+from
+t2 a inner join t3 b on a.id = b.forum inner join
+t1 c on b.id = c.thread
+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
+drop table t1,t2,t3;
diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result
index f4091ff4c0e..50889943b56 100644
--- a/mysql-test/r/func_date_add.result
+++ b/mysql-test/r/func_date_add.result
@@ -4,7 +4,7 @@ visitor_id int(10) unsigned DEFAULT '0' NOT NULL,
group_id int(10) unsigned DEFAULT '0' NOT NULL,
hits int(10) unsigned DEFAULT '0' NOT NULL,
sessions int(10) unsigned DEFAULT '0' NOT NULL,
-ts timestamp(14),
+ts timestamp,
PRIMARY KEY (visitor_id,group_id)
)/*! engine=MyISAM */;
INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952);
diff --git a/mysql-test/r/func_des_encrypt.result b/mysql-test/r/func_des_encrypt.result
new file mode 100644
index 00000000000..46b30bdab58
--- /dev/null
+++ b/mysql-test/r/func_des_encrypt.result
@@ -0,0 +1,3 @@
+select des_encrypt('hello');
+des_encrypt('hello')
+€Ö2nV“Ø}
diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result
index d32e67fe7d5..3eb8ec4354c 100644
--- a/mysql-test/r/func_encrypt.result
+++ b/mysql-test/r/func_encrypt.result
@@ -120,6 +120,48 @@ hello
select des_decrypt(des_encrypt("hello",4),'password4');
des_decrypt(des_encrypt("hello",4),'password4')
hello
+select des_encrypt("hello",10);
+des_encrypt("hello",10)
+NULL
+Warnings:
+Error 1108 Incorrect parameters to procedure 'des_encrypt'
+select des_encrypt(NULL);
+des_encrypt(NULL)
+NULL
+select des_encrypt(NULL, 10);
+des_encrypt(NULL, 10)
+NULL
+select des_encrypt(NULL, NULL);
+des_encrypt(NULL, NULL)
+NULL
+select des_encrypt(10, NULL);
+des_encrypt(10, NULL)
+NULL
+Warnings:
+Error 1108 Incorrect parameters to procedure 'des_encrypt'
+select des_encrypt("hello", NULL);
+des_encrypt("hello", NULL)
+NULL
+Warnings:
+Error 1108 Incorrect parameters to procedure 'des_encrypt'
+select des_decrypt("hello",10);
+des_decrypt("hello",10)
+hello
+select des_decrypt(NULL);
+des_decrypt(NULL)
+NULL
+select des_decrypt(NULL, 10);
+des_decrypt(NULL, 10)
+NULL
+select des_decrypt(NULL, NULL);
+des_decrypt(NULL, NULL)
+NULL
+select des_decrypt(10, NULL);
+des_decrypt(10, NULL)
+10
+select des_decrypt("hello", NULL);
+des_decrypt("hello", NULL)
+hello
SET @a=des_decrypt(des_encrypt("hello"));
flush des_key_file;
select @a = des_decrypt(des_encrypt("hello"));
@@ -134,6 +176,8 @@ NULL
select hex(des_decrypt(des_encrypt("hello","hidden")));
hex(des_decrypt(des_encrypt("hello","hidden")))
NULL
+Warnings:
+Error 1108 Incorrect parameters to procedure 'des_decrypt'
explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden"));
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
diff --git a/mysql-test/r/func_encrypt_nossl.result b/mysql-test/r/func_encrypt_nossl.result
new file mode 100644
index 00000000000..d0df2335afa
--- /dev/null
+++ b/mysql-test/r/func_encrypt_nossl.result
@@ -0,0 +1,98 @@
+select des_encrypt("test", 'akeystr');
+des_encrypt("test", 'akeystr')
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_encrypt("test", 1);
+des_encrypt("test", 1)
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_encrypt("test", 9);
+des_encrypt("test", 9)
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_encrypt("test", 100);
+des_encrypt("test", 100)
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_encrypt("test", NULL);
+des_encrypt("test", NULL)
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_encrypt(NULL, NULL);
+des_encrypt(NULL, NULL)
+NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt("test", 'anotherkeystr');
+des_decrypt("test", 'anotherkeystr')
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(1, 1);
+des_decrypt(1, 1)
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(des_encrypt("test", 'thekey'));
+des_decrypt(des_encrypt("test", 'thekey'))
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello"));
+hex(des_encrypt("hello")) des_decrypt(des_encrypt("hello"))
+NULL NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(des_encrypt("hello",4));
+des_decrypt(des_encrypt("hello",4))
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(des_encrypt("hello",'test'),'test');
+des_decrypt(des_encrypt("hello",'test'),'test')
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password'));
+hex(des_encrypt("hello")) hex(des_encrypt("hello",5)) hex(des_encrypt("hello",'default_password'))
+NULL NULL NULL
+Warnings:
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(des_encrypt("hello"),'default_password');
+des_decrypt(des_encrypt("hello"),'default_password')
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select des_decrypt(des_encrypt("hello",4),'password4');
+des_decrypt(des_encrypt("hello",4),'password4')
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+SET @a=des_decrypt(des_encrypt("hello"));
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+flush des_key_file;
+select @a = des_decrypt(des_encrypt("hello"));
+@a = des_decrypt(des_encrypt("hello"))
+NULL
+select hex("hello");
+hex("hello")
+68656C6C6F
+select hex(des_decrypt(des_encrypt("hello",4),'password2'));
+hex(des_decrypt(des_encrypt("hello",4),'password2'))
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
+select hex(des_decrypt(des_encrypt("hello","hidden")));
+hex(des_decrypt(des_encrypt("hello","hidden")))
+NULL
+Warnings:
+Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 1c6a4393dfc..5335f53d382 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -264,7 +264,7 @@ category int(10) unsigned default NULL,
program int(10) unsigned default NULL,
bugdesc text,
created datetime default NULL,
-modified timestamp(14) NOT NULL,
+modified timestamp NOT NULL,
bugstatus int(10) unsigned default NULL,
submitter int(10) unsigned default NULL
) ENGINE=MyISAM;
@@ -800,3 +800,82 @@ field(0,NULL,1,0) field("",NULL,"bar","") field(0.0,NULL,1.0,0.0)
select field(NULL,1,2,NULL), field(NULL,1,2,0);
field(NULL,1,2,NULL) field(NULL,1,2,0)
0 0
+CREATE TABLE t1 (str varchar(20) PRIMARY KEY);
+CREATE TABLE t2 (num int primary key);
+INSERT INTO t1 VALUES ('notnumber');
+INSERT INTO t2 VALUES (0), (1);
+SELECT * FROM t1, t2 WHERE num=str;
+str num
+notnumber 0
+SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6);
+str num
+notnumber 0
+DROP TABLE t1,t2;
+CREATE TABLE t1(
+id int(11) NOT NULL auto_increment,
+pc int(11) NOT NULL default '0',
+title varchar(20) default NULL,
+PRIMARY KEY (id)
+);
+INSERT INTO t1 VALUES
+(1, 0, 'Main'),
+(2, 1, 'Toys'),
+(3, 1, 'Games');
+SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1
+FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id
+LEFT JOIN t1 AS t3 ON t2.pc=t3.id;
+id col1
+1 Main
+2 Main->Toys
+3 Main->Games
+SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1
+FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id
+LEFT JOIN t1 AS t3 ON t2.pc=t3.id
+WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%';
+id col1
+2 Main->Toys
+DROP TABLE t1;
+CREATE TABLE t1(
+trackid int(10) unsigned NOT NULL auto_increment,
+trackname varchar(100) NOT NULL default '',
+PRIMARY KEY (trackid)
+);
+CREATE TABLE t2(
+artistid int(10) unsigned NOT NULL auto_increment,
+artistname varchar(100) NOT NULL default '',
+PRIMARY KEY (artistid)
+);
+CREATE TABLE t3(
+trackid int(10) unsigned NOT NULL,
+artistid int(10) unsigned NOT NULL,
+PRIMARY KEY (trackid,artistid)
+);
+INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York');
+INSERT INTO t2 VALUES (1, 'Vernon Duke');
+INSERT INTO t3 VALUES (1,1);
+SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname
+FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid
+LEFT JOIN t2 ON t2.artistid=t3.artistid
+WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%';
+trackname artistname
+April In Paris Vernon Duke Vernon Duke
+Autumn In New York NULL
+DROP TABLE t1,t2,t3;
+create table t1 (b varchar(5));
+insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde');
+select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1;
+b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5)
+ab ab b ab
+abc abc c bc abc
+abcd abcd d cd bcd abcd
+abcde abcde e de cde bcde abcde
+select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t;
+b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5)
+ab ab b ab
+abc abc c bc abc
+abcd abcd d cd bcd abcd
+abcde abcde e de cde bcde abcde
+drop table t1;
+select hex(29223372036854775809), hex(-29223372036854775809);
+hex(29223372036854775809) hex(-29223372036854775809)
+FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index cb51da75368..63da5589c57 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -465,7 +465,7 @@ extract(MONTH FROM "0000-00-00") extract(MONTH FROM d) extract(MONTH FROM dt) ex
drop table t1;
CREATE TABLE t1 ( start datetime default NULL);
INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00');
-CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL);
+CREATE TABLE t2 ( ctime1 timestamp NOT NULL, ctime2 timestamp NOT NULL);
INSERT INTO t2 VALUES (20021029165106,20021105164731);
CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL);
INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31");
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index c8ae8303d99..19982c7bb60 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -1,4 +1,5 @@
drop table if exists t1;
+drop database if exists mysqltest;
SET NAMES binary;
delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1';
@@ -473,3 +474,120 @@ ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
delete from mysql.user where user=_binary'mysqltest_1';
drop database mysqltest;
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE
+mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE
+mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE
+SHOW FIELDS FROM mysql.tables_priv;
+Field Type Null Key Default Extra
+Host char(60) NO PRI
+Db char(64) NO PRI
+User char(16) NO PRI
+Table_name char(64) NO PRI
+Grantor char(77) NO MUL
+Timestamp timestamp YES CURRENT_TIMESTAMP
+Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') NO
+Column_priv set('Select','Insert','Update','References') NO
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost;
+GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable CREATE VIEW
+mysqltest dummyview CREATE VIEW
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable CREATE VIEW
+mysqltest dummyview CREATE VIEW
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost;
+GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable SHOW VIEW
+mysqltest dummyview SHOW VIEW
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost'
+GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost'
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+TABLE_SCHEMA TABLE_NAME PRIVILEGES
+mysqltest dummytable SHOW VIEW
+mysqltest dummyview SHOW VIEW
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+use mysql;
+insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select');
+flush privileges;
+delete from tables_priv where host = '' and user = 'mysqltest_1';
+flush privileges;
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index 6e36d32bd2b..64446e63e6f 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -117,7 +117,7 @@ bug_file_loc text,
bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL,
bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL,
creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-delta_ts timestamp(14),
+delta_ts timestamp,
short_desc mediumtext,
long_desc mediumtext,
op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL,
@@ -723,6 +723,42 @@ WHERE hostname LIKE '%aol%'
hostname no
cache-dtc-af05.proxy.aol.com 1
DROP TABLE t1;
+CREATE TABLE t1 (a int, b int);
+INSERT INTO t1 VALUES (1,2), (1,3);
+SELECT a, b FROM t1 GROUP BY 'const';
+a b
+1 2
+SELECT DISTINCT a, b FROM t1 GROUP BY 'const';
+a b
+1 2
+DROP TABLE t1;
+CREATE TABLE t1 (id INT, dt DATETIME);
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f;
+f id
+20050501123000 1
+DROP TABLE t1;
+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;
+COUNT(DISTINCT(t1.id)) comment
+1 NULL
+1 a problem
+DROP TABLE t1, t2;
+CREATE TABLE t1 (n int);
+INSERT INTO t1 VALUES (1);
+SELECT n+1 AS n FROM t1 GROUP BY n;
+n
+2
+Warnings:
+Warning 1052 Column 'n' in group statement is ambiguous
+DROP TABLE t1;
create table t1 (c1 char(3), c2 char(3));
create table t2 (c3 char(3), c4 char(3));
insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2');
@@ -744,12 +780,3 @@ aaa
show warnings;
Level Code Message
drop table t1, t2;
-CREATE TABLE t1 (a int, b int);
-INSERT INTO t1 VALUES (1,2), (1,3);
-SELECT a, b FROM t1 GROUP BY 'const';
-a b
-1 2
-SELECT DISTINCT a, b FROM t1 GROUP BY 'const';
-a b
-1 2
-DROP TABLE t1;
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index 22304c4a93d..b905dae3aba 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -367,13 +367,13 @@ count(*)
9
explain select count(*) from t1 where v='a ';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref v v 13 const 9 Using where
+1 SIMPLE t1 ref v v 13 const 10 Using where
explain select count(*) from t1 where c='a ';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref c c 11 const 9 Using where
+1 SIMPLE t1 ref c c 11 const 10 Using where
explain select count(*) from t1 where t='a ';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref t t 13 const 9 Using where
+1 SIMPLE t1 ref t t 13 const 10 Using where
explain select count(*) from t1 where v like 'a%';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where
@@ -399,7 +399,7 @@ qq
*a *a*a *
explain select * from t1 where v='a';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref v v 13 const 9 Using where
+1 SIMPLE t1 ref v v 13 const 10 Using where
select v,count(*) from t1 group by v limit 10;
v count(*)
a 1
diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result
index 9720fe4843a..d8d89b786b5 100644
--- a/mysql-test/r/heap_hash.result
+++ b/mysql-test/r/heap_hash.result
@@ -231,18 +231,19 @@ explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 8 const 1 Using where
insert into t1 select * from t1;
+flush tables;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
flush tables;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
@@ -261,16 +262,16 @@ delete from t1;
insert into t1 select * from t2;
explain select * from t1 where a='aaaa';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaab';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaac';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
explain select * from t1 where a='aaad';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref a a 8 const 1 Using where
+1 SIMPLE t1 ref a a 8 const 2 Using where
drop table t1, t2;
create table t1 (
id int unsigned not null primary key auto_increment,
@@ -345,15 +346,15 @@ insert into t3 select name, name from t1;
show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH
-t3 1 a 2 b NULL 15 NULL NULL HASH
+t3 1 a 2 b NULL 13 NULL NULL HASH
show index from t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t3 1 a 1 a NULL NULL NULL NULL HASH
-t3 1 a 2 b NULL 15 NULL NULL HASH
+t3 1 a 2 b NULL 13 NULL NULL HASH
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 ref a a 44 const,const 6 Using where
1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where
+1 SIMPLE t3 ref a a 44 const,const 7 Using where
drop table t1, t2, t3;
create temporary table t1 ( a int, index (a) ) engine=memory;
insert into t1 values (1),(2),(3),(4),(5);
diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result
index 8f5db550d8b..d039d5a04c9 100644
--- a/mysql-test/r/index_merge.result
+++ b/mysql-test/r/index_merge.result
@@ -371,8 +371,8 @@ alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(20
update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
from t0 as A, t0 as B
-where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key# = 1 or A.key8=1)
-and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key# = 1 or B.key8=1);
+where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
+and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL # Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where
1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL # Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where
diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result
index 52e2a4046cf..662fffe1ba1 100644
--- a/mysql-test/r/index_merge_innodb.result
+++ b/mysql-test/r/index_merge_innodb.result
@@ -123,3 +123,14 @@ key1a = 2 and key1b is null and key3a = 2 and key3b is null;
count(*)
4
drop table t1,t2;
+create table t1 (
+id1 int,
+id2 date ,
+index idx2 (id1,id2),
+index idx1 (id2)
+) engine = innodb;
+insert into t1 values(1,'20040101'), (2,'20040102');
+select * from t1 where id1 = 1 and id2= '20040101';
+id1 id2
+1 2004-01-01
+drop table t1;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index c6090bc663d..98f3d59485f 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -227,6 +227,9 @@ latin1_bin latin1
latin1_general_ci latin1
latin1_general_cs latin1
latin1_spanish_ci latin1
+drop procedure if exists sel2;
+drop function if exists sub1;
+drop function if exists sub2;
create function sub1(i int) returns int
return i+1;
create procedure sel2()
@@ -671,7 +674,7 @@ Database Table In_use Name_locked
mysql user 0 0
show status where variable_name like "%database%";
Variable_name Value
-Com_show_databases 0
+Com_show_databases 3
show variables where variable_name like "skip_show_databas";
Variable_name Value
show global status like "Threads_running";
@@ -735,7 +738,7 @@ x_real NULL NULL
x_float NULL NULL
x_double_precision NULL NULL
drop table t1;
-create user mysqltest_4@localhost;
+grant select on test.* to mysqltest_4@localhost;
SELECT TABLE_NAME, COLUMN_NAME, PRIVILEGES FROM INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME='TABLE_NAME';
TABLE_NAME COLUMN_NAME PRIVILEGES
@@ -748,6 +751,7 @@ COLUMN_PRIVILEGES TABLE_NAME select
TABLE_CONSTRAINTS TABLE_NAME select
KEY_COLUMN_USAGE TABLE_NAME select
delete from mysql.user where user='mysqltest_4';
+delete from mysql.db where user='mysqltest_4';
flush privileges;
SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA;
table_schema count(*)
@@ -823,6 +827,8 @@ GRANT SELECT ON *.* TO 'user4'@'localhost'
drop user user1@localhost, user2@localhost, user3@localhost, user4@localhost;
use test;
drop database mysqltest;
+drop procedure if exists p1;
+drop procedure if exists p2;
create procedure p1 () modifies sql data set @a = 5;
create procedure p2 () set @a = 5;
select sql_data_access from information_schema.routines
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 24ba58e0b68..2c73cbeeea4 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -972,9 +972,9 @@ number bigint(20) NOT NULL default '0',
cname char(15) NOT NULL default '',
carrier_id smallint(6) NOT NULL default '0',
privacy tinyint(4) NOT NULL default '0',
-last_mod_date timestamp(14) NOT NULL,
+last_mod_date timestamp NOT NULL,
last_mod_id smallint(6) NOT NULL default '0',
-last_app_date timestamp(14) NOT NULL,
+last_app_date timestamp NOT NULL,
last_app_id smallint(6) default '-1',
version smallint(6) NOT NULL default '0',
assigned_scps int(11) default '0',
@@ -991,9 +991,9 @@ number bigint(20) NOT NULL default '0',
cname char(15) NOT NULL default '',
carrier_id smallint(6) NOT NULL default '0',
privacy tinyint(4) NOT NULL default '0',
-last_mod_date timestamp(14) NOT NULL,
+last_mod_date timestamp NOT NULL,
last_mod_id smallint(6) NOT NULL default '0',
-last_app_date timestamp(14) NOT NULL,
+last_app_date timestamp NOT NULL,
last_app_id smallint(6) default '-1',
version smallint(6) NOT NULL default '0',
assigned_scps int(11) default '0',
@@ -1721,12 +1721,13 @@ count(*)
0
explain select count(*) from t1 where x > -16;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL 1 Using where; Using index
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 2 Using where; Using index
select count(*) from t1 where x > -16;
count(*)
-1
+2
select * from t1 where x > -16;
x
+18446744073709551600
18446744073709551601
select count(*) from t1 where x = 18446744073709551601;
count(*)
@@ -1779,7 +1780,7 @@ Variable_name Value
innodb_sync_spin_loops 20
show variables like "innodb_thread_concurrency";
Variable_name Value
-innodb_thread_concurrency 8
+innodb_thread_concurrency 20
set global innodb_thread_concurrency=1000;
show variables like "innodb_thread_concurrency";
Variable_name Value
@@ -2465,3 +2466,12 @@ select * from t1;
a val
2 1
drop table t1;
+CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB;
+INSERT INTO t1 (GRADE) VALUES (151),(252),(343);
+SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300;
+GRADE
+252
+SELECT GRADE FROM t1 WHERE GRADE= 151;
+GRADE
+151
+DROP TABLE t1;
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index d2c0a665845..f745af182eb 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL);
insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12);
create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY);
@@ -625,3 +625,46 @@ select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1);
ID NO SEQ
1 1 1
drop table t1;
+create table t1 (f1 int);
+create table t2 (ff1 int unique, ff2 int default 1);
+insert into t1 values (1),(1),(2);
+insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1;
+select * from t2;
+ff1 ff2
+1 2
+2 1
+drop table t1, t2;
+create table t1 (a int unique);
+create table t2 (a int, b int);
+create table t3 (c int, d int);
+insert into t1 values (1),(2);
+insert into t2 values (1,2);
+insert into t3 values (1,6),(3,7);
+select * from t1;
+a
+1
+2
+insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b;
+select * from t1;
+a
+2
+3
+insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1;
+select * from t1;
+a
+3
+5
+insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d;
+select * from t1;
+a
+1
+5
+10
+insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10;
+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
+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
+drop table t1,t2,t3;
diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result
index 6d3aa941c8c..fc157093a7f 100644
--- a/mysql-test/r/insert_update.result
+++ b/mysql-test/r/insert_update.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B));
INSERT t1 VALUES (1,2,10), (3,4,20);
INSERT t1 VALUES (5,6,30) ON DUPLICATE KEY UPDATE c=c+100;
@@ -143,7 +143,7 @@ INSERT t1 VALUES (1,2,10), (3,4,20);
CREATE TABLE t2 (a INT, b INT, c INT, d INT);
INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1);
INSERT t2 VALUES (2,1,11,2), (7,4,40,2);
-INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100;
+INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100;
SELECT * FROM t1;
a b c
1 2 10
@@ -158,6 +158,8 @@ a b c
5 0 30
8 9 60
INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a);
+ERROR 23000: Column 'c' in field list is ambiguous
+INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a);
SELECT *, VALUES(a) FROM t1;
a b c VALUES(a)
1 2 10 NULL
@@ -174,7 +176,7 @@ select * from t1;
a
1
2
-insert ignore into t1 select a from t1 on duplicate key update a=a+1 ;
+insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ;
select * from t1;
a
1
@@ -185,5 +187,7 @@ a
2
3
insert into t1 select a from t1 on duplicate key update a=a+1 ;
-ERROR 23000: Duplicate entry '3' for key 1
+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;
diff --git a/mysql-test/r/lowercase_table2.result b/mysql-test/r/lowercase_table2.result
index db833bcd970..44235cbf900 100644
--- a/mysql-test/r/lowercase_table2.result
+++ b/mysql-test/r/lowercase_table2.result
@@ -1,6 +1,7 @@
-DROP TABLE IF EXISTS t1,t2,t3;
+DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa;
DROP DATABASE IF EXISTS `TEST_$1`;
DROP DATABASE IF EXISTS `test_$1`;
+DROP DATABASE IF EXISTS mysqltest_LC2;
CREATE TABLE T1 (a int);
INSERT INTO T1 VALUES (1);
SHOW TABLES LIKE "T1";
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 080bc4d1e0f..be2003bbc67 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -1,11 +1,11 @@
DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
drop database if exists mysqldump_test_db;
drop database if exists db1;
-drop view if exists v1, v2;
+drop view if exists v1, v2, v3;
CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
<?xml version="1.0"?>
-<mysqldump>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<table_structure name="t1">
<field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
@@ -108,7 +108,7 @@ DROP TABLE t1;
CREATE TABLE t1(a int, b text, c varchar(3));
INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES");
<?xml version="1.0"?>
-<mysqldump>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<table_structure name="t1">
<field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
@@ -133,7 +133,7 @@ DROP TABLE t1;
CREATE TABLE t1 (`a"b"` char(2));
INSERT INTO t1 VALUES ("1\""), ("\"2");
<?xml version="1.0"?>
-<mysqldump>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<table_structure name="t1">
<field Field="a&quot;b&quot;" Type="char(2)" Null="YES" Key="" Extra="" />
@@ -380,6 +380,11 @@ UNLOCK TABLES;
/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
DROP TABLE IF EXISTS `v1`;
DROP VIEW IF EXISTS `v1`;
+CREATE TABLE `v1` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `v1`;
+DROP VIEW IF EXISTS `v1`;
CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@@ -1458,6 +1463,11 @@ UNLOCK TABLES;
/*!40000 ALTER TABLE `t2` ENABLE KEYS */;
DROP TABLE IF EXISTS `v2`;
DROP VIEW IF EXISTS `v2`;
+CREATE TABLE `v2` (
+ `a` varchar(30) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `v2`;
+DROP VIEW IF EXISTS `v2`;
CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from `db1`.`t2` where (`db1`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
@@ -1471,3 +1481,195 @@ CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from
drop table t2;
drop view v2;
drop database db1;
+CREATE DATABASE mysqldump_test_db;
+USE mysqldump_test_db;
+CREATE TABLE t1 ( a INT );
+CREATE TABLE t2 ( a INT );
+INSERT INTO t1 VALUES (1), (2);
+INSERT INTO t2 VALUES (1), (2);
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `t2`;
+CREATE TABLE `t2` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `t2`;
+CREATE TABLE `t2` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+<?xml version="1.0"?>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<database name="mysqldump_test_db">
+ <table_structure name="t1">
+ <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
+ </table_structure>
+ <table_structure name="t2">
+ <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
+ </table_structure>
+</database>
+</mysqldump>
+<?xml version="1.0"?>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<database name="mysqldump_test_db">
+ <table_structure name="t1">
+ <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
+ </table_structure>
+ <table_structure name="t2">
+ <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
+ </table_structure>
+</database>
+</mysqldump>
+DROP TABLE t1, t2;
+DROP DATABASE mysqldump_test_db;
+create database mysqldump_test_db;
+use mysqldump_test_db;
+create table t1(a varchar(30) primary key, b int not null);
+create table t2(a varchar(30) primary key, b int not null);
+create table t3(a varchar(30) primary key, b int not null);
+test_sequence
+------ Testing with illegal table names ------
+mysqldump: Couldn't find table: "\d-2-1.sql"
+
+mysqldump: Couldn't find table: "\t1"
+
+mysqldump: Couldn't find table: "\t1"
+
+mysqldump: Couldn't find table: "\\t1"
+
+mysqldump: Couldn't find table: "t\1"
+
+mysqldump: Couldn't find table: "t\1"
+
+mysqldump: Couldn't find table: "t/1"
+
+test_sequence
+------ Testing with illegal database names ------
+mysqldump: Got error: 1049: Unknown database 'mysqldump_test_d' when selecting the database
+mysqldump: Got error: 1102: Incorrect database name 'mysqld\ump_test_db' when selecting the database
+drop table t1, t2, t3;
+drop database mysqldump_test_db;
+use test;
+create table t1 (a int(10));
+create table t2 (pk int primary key auto_increment,
+a int(10), b varchar(30), c datetime, d blob, e text);
+insert into t1 values (NULL), (10), (20);
+insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thirty");
+<?xml version="1.0"?>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<database name="test">
+ <table_data name="t1">
+ <row>
+ <field name="a" xsi:nil="true" />
+ </row>
+ <row>
+ <field name="a">10</field>
+ </row>
+ <row>
+ <field name="a">20</field>
+ </row>
+ </table_data>
+ <table_data name="t2">
+ <row>
+ <field name="pk">1</field>
+ <field name="a" xsi:nil="true" />
+ <field name="b" xsi:nil="true" />
+ <field name="c" xsi:nil="true" />
+ <field name="d" xsi:nil="true" />
+ <field name="e" xsi:nil="true" />
+ </row>
+ <row>
+ <field name="pk">2</field>
+ <field name="a">10</field>
+ <field name="b" xsi:nil="true" />
+ <field name="c" xsi:nil="true" />
+ <field name="d" xsi:nil="true" />
+ <field name="e" xsi:nil="true" />
+ </row>
+ <row>
+ <field name="pk">3</field>
+ <field name="a" xsi:nil="true" />
+ <field name="b">twenty</field>
+ <field name="c" xsi:nil="true" />
+ <field name="d" xsi:nil="true" />
+ <field name="e" xsi:nil="true" />
+ </row>
+ <row>
+ <field name="pk">4</field>
+ <field name="a">30</field>
+ <field name="b">thirty</field>
+ <field name="c" xsi:nil="true" />
+ <field name="d" xsi:nil="true" />
+ <field name="e" xsi:nil="true" />
+ </row>
+ </table_data>
+</database>
+</mysqldump>
+drop table t1, t2;
+create table t1(a int, b int, c varchar(30));
+insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three");
+create view v3 as
+select * from t1;
+create view v1 as
+select * from v3 where b in (1, 2, 3, 4, 5, 6, 7);
+create view v2 as
+select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1;
+drop view v1, v2, v3;
+drop table t1;
+show full tables;
+Tables_in_test Table_type
+t1 BASE TABLE
+v1 VIEW
+v2 VIEW
+v3 VIEW
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `v3`.`a` AS `a`,`v3`.`b` AS `b`,`v3`.`c` AS `c` from `test`.`v3` where (`v3`.`b` in (1,2,3,4,5,6,7))
+select * from v1;
+a b c
+1 2 one
+2 4 two
+3 6 three
+drop view v1, v2, v3;
+drop table t1;
diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result
index 27ebda36669..0f17160ea99 100644
--- a/mysql-test/r/ndb_autodiscover.result
+++ b/mysql-test/r/ndb_autodiscover.result
@@ -93,7 +93,7 @@ name char(20), a int, b float, c char(24)
ERROR 42S01: Table 't3' already exists
show status like 'handler_discover%';
Variable_name Value
-Handler_discover 1
+Handler_discover 0
create table IF NOT EXISTS t3(
id int not null primary key,
id2 int not null,
@@ -101,7 +101,7 @@ name char(20)
) engine=ndb;
show status like 'handler_discover%';
Variable_name Value
-Handler_discover 2
+Handler_discover 0
SHOW CREATE TABLE t3;
Table Create Table
t3 CREATE TABLE `t3` (
@@ -114,7 +114,7 @@ id name
1 Explorer
show status like 'handler_discover%';
Variable_name Value
-Handler_discover 2
+Handler_discover 1
drop table t3;
flush status;
create table t7(
diff --git a/mysql-test/r/ndb_insert.result b/mysql-test/r/ndb_insert.result
index 7503010a66b..464eeb6d607 100644
--- a/mysql-test/r/ndb_insert.result
+++ b/mysql-test/r/ndb_insert.result
@@ -416,10 +416,12 @@ INSERT INTO t1 VALUES
SELECT COUNT(*) FROM t1;
COUNT(*)
2000
+INSERT INTO t1 VALUES (1,1,1);
+ERROR 23000: Duplicate entry '1' for key 1
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
select count(*) from t1;
count(*)
2000
@@ -437,7 +439,7 @@ begin;
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
commit;
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
select * from t1 where pk1=1;
@@ -456,7 +458,7 @@ begin;
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
rollback;
select * from t1 where pk1=1;
pk1 b c
@@ -474,7 +476,7 @@ begin;
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
SELECT * FROM t1 WHERE pk1=10;
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
rollback;
@@ -494,7 +496,7 @@ begin;
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
SELECT * FROM t1 WHERE pk1=10;
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
SELECT * FROM t1 WHERE pk1=10;
@@ -517,7 +519,7 @@ begin;
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
-ERROR 23000: Duplicate entry '10' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
INSERT INTO t1 values (4000, 40, 44);
ERROR HY000: Got error 4350 'Transaction already aborted' from ndbcluster
rollback;
@@ -534,7 +536,7 @@ select count(*) from t1;
count(*)
2000
insert into t1 select * from t1 where b < 10 order by pk1;
-ERROR 23000: Duplicate entry '9' for key 1
+ERROR 23000: Can't write; duplicate key in table 't1'
DELETE FROM t1 WHERE pk1=2;
begin;
INSERT IGNORE INTO t1 VALUES(1,2,3),(2,3,4);
diff --git a/mysql-test/r/ndb_subquery.result b/mysql-test/r/ndb_subquery.result
index f65f09b71b3..b19571b05c1 100644
--- a/mysql-test/r/ndb_subquery.result
+++ b/mysql-test/r/ndb_subquery.result
@@ -40,3 +40,22 @@ p u o
5 5 5
drop table t1;
drop table t2;
+create table t1 (p int not null primary key, u int not null) engine=ndb;
+insert into t1 values (1,1),(2,2),(3,3);
+create table t2 as
+select t1.*
+from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8
+where t1.u = t2.u
+and t2.u = t3.u
+and t3.u = t4.u
+and t4.u = t5.u
+and t5.u = t6.u
+and t6.u = t7.u
+and t7.u = t8.u;
+select * from t2 order by 1;
+p u
+1 1
+2 2
+3 3
+drop table t1;
+drop table t2;
diff --git a/mysql-test/r/not_openssl.require b/mysql-test/r/not_openssl.require
new file mode 100644
index 00000000000..2b5e423999c
--- /dev/null
+++ b/mysql-test/r/not_openssl.require
@@ -0,0 +1,2 @@
+Variable_name Value
+have_openssl NO
diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result
index c37a42d3fa7..a19734d55b5 100644
--- a/mysql-test/r/olap.result
+++ b/mysql-test/r/olap.result
@@ -555,3 +555,25 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST')
4 TEST
TEST TEST
DROP TABLE t1,t2;
+CREATE TABLE t1(id int, type char(1));
+INSERT INTO t1 VALUES
+(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"),
+(6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C");
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT type FROM t1 GROUP BY type WITH ROLLUP;
+type
+A
+B
+C
+NULL
+SELECT type FROM v1 GROUP BY type WITH ROLLUP;
+type
+A
+B
+C
+NULL
+EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 496d566a5ee..0050dfc0841 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -138,7 +138,7 @@ create table t1
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 bit, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -675,3 +675,128 @@ a
10
drop table t1;
deallocate prepare stmt;
+create table t1 (id int);
+prepare stmt from "insert into t1 (id) select id from t1 union select id from t1";
+execute stmt;
+execute stmt;
+deallocate prepare stmt;
+drop table t1;
+create table t1 (
+id int(11) unsigned not null primary key auto_increment,
+partner_id varchar(35) not null,
+t1_status_id int(10) unsigned
+);
+insert into t1 values ("1", "partner1", "10"), ("2", "partner2", "10"),
+("3", "partner3", "10"), ("4", "partner4", "10");
+create table t2 (
+id int(11) unsigned not null default '0',
+t1_line_id int(11) unsigned not null default '0',
+article_id varchar(20),
+sequence int(11) not null default '0',
+primary key (id,t1_line_id)
+);
+insert into t2 values ("1", "1", "sup", "0"), ("2", "1", "sup", "1"),
+("2", "2", "sup", "2"), ("2", "3", "sup", "3"),
+("2", "4", "imp", "4"), ("3", "1", "sup", "0"),
+("4", "1", "sup", "0");
+create table t3 (
+id int(11) not null default '0',
+preceeding_id int(11) not null default '0',
+primary key (id,preceeding_id)
+);
+create table t4 (
+user_id varchar(50) not null,
+article_id varchar(20) not null,
+primary key (user_id,article_id)
+);
+insert into t4 values("nicke", "imp");
+prepare stmt from
+'select distinct t1.partner_id
+from t1 left join t3 on t1.id = t3.id
+ left join t1 pp on pp.id = t3.preceeding_id
+where
+ exists (
+ select *
+ from t2 as pl_inner
+ where pl_inner.id = t1.id
+ and pl_inner.sequence <= (
+ select min(sequence) from t2 pl_seqnr
+ where pl_seqnr.id = t1.id
+ )
+ and exists (
+ select * from t4
+ where t4.article_id = pl_inner.article_id
+ and t4.user_id = ?
+ )
+ )
+ and t1.id = ?
+group by t1.id
+having count(pp.id) = 0';
+set @user_id = 'nicke';
+set @id = '2';
+execute stmt using @user_id, @id;
+partner_id
+execute stmt using @user_id, @id;
+partner_id
+deallocate prepare stmt;
+drop table t1, t2, t3, t4;
+prepare stmt from 'select ?=?';
+set @a='CHRISTINE ';
+set @b='CHRISTINE';
+execute stmt using @a, @b;
+?=?
+1
+execute stmt using @a, @b;
+?=?
+1
+set @a=1, @b=2;
+execute stmt using @a, @b;
+?=?
+0
+set @a='CHRISTINE ';
+set @b='CHRISTINE';
+execute stmt using @a, @b;
+?=?
+1
+deallocate prepare stmt;
+create table t1 (a int);
+prepare stmt from "select ??";
+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
+prepare stmt from "select ?FROM t1";
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?FROM t1' at line 1
+prepare stmt from "select FROM t1 WHERE?=1";
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM t1 WHERE?=1' at line 1
+prepare stmt from "update t1 set a=a+?WHERE 1";
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?WHERE 1' at line 1
+select ?;
+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 ??;
+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;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1
+drop table t1;
+prepare stmt from "select @@time_zone";
+execute stmt;
+@@time_zone
+SYSTEM
+set @@time_zone:='Japan';
+execute stmt;
+@@time_zone
+Japan
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+set transaction isolation level read committed;
+execute stmt;
+@@tx_isolation
+READ-COMMITTED
+set transaction isolation level serializable;
+execute stmt;
+@@tx_isolation
+SERIALIZABLE
+set @@tx_isolation=default;
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+deallocate prepare stmt;
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index 54c35873201..f2d60ac5025 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -17,7 +17,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -290,11 +290,11 @@ t2 1 t2_idx 1 b A NULL NULL NULL YES BTREE
prepare stmt4 from ' show table status from test like ''t2%'' ';
execute stmt4;
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 4222124650659839 1024 0 NULL # # # latin1_swedish_ci NULL
+t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # # latin1_swedish_ci NULL
prepare stmt4 from ' show table status from test like ''t9%'' ';
execute stmt4;
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
-t9 MyISAM 10 Dynamic 2 216 432 281474976710655 2048 0 NULL # # # latin1_swedish_ci NULL
+t9 MyISAM 10 Dynamic 2 216 432 # 2048 0 NULL # # # latin1_swedish_ci NULL
prepare stmt4 from ' show status like ''Threads_running'' ';
execute stmt4;
Variable_name Value
diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result
index 5e839bf4a02..64dc09f864c 100644
--- a/mysql-test/r/ps_2myisam.result
+++ b/mysql-test/r/ps_2myisam.result
@@ -10,7 +10,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -1810,17 +1810,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1828,8 +1828,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result
index c5d5895adca..792d74231f2 100644
--- a/mysql-test/r/ps_3innodb.result
+++ b/mysql-test/r/ps_3innodb.result
@@ -10,7 +10,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result
index 8d703ec1ea5..7dcb8546a83 100644
--- a/mysql-test/r/ps_4heap.result
+++ b/mysql-test/r/ps_4heap.result
@@ -11,7 +11,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 varchar(100), c24 varchar(100),
c25 varchar(100), c26 varchar(100), c27 varchar(100), c28 varchar(100),
@@ -1794,17 +1794,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1812,8 +1812,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result
index 72b0fac4201..77b1a242452 100644
--- a/mysql-test/r/ps_5merge.result
+++ b/mysql-test/r/ps_5merge.result
@@ -12,7 +12,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -32,7 +32,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -52,7 +52,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -120,8 +120,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -1730,17 +1730,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1748,8 +1748,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
@@ -3064,7 +3064,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -3132,8 +3132,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -4742,17 +4742,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -4760,8 +4760,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result
index 87b1b110f42..0489c7ef078 100644
--- a/mysql-test/r/ps_6bdb.result
+++ b/mysql-test/r/ps_6bdb.result
@@ -10,7 +10,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result
index c158156d11d..b0049b3e943 100644
--- a/mysql-test/r/ps_7ndb.result
+++ b/mysql-test/r/ps_7ndb.result
@@ -10,7 +10,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
-c13 date, c14 datetime, c15 timestamp(14), c16 time,
+c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
-def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63
-def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
def test t9 t9 c31 c31 254 5 3 Y 256 0 8
def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
@@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63
def test t5 t5 const03 const03 5 17 1 N 32769 31 63
def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
def test t5 t5 const04 const04 253 3 3 N 1 0 8
-def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
def test t5 t5 const05 const05 253 3 3 N 129 0 63
-def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
def test t5 t5 const06 const06 253 10 10 N 1 0 8
-def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
def test t5 t5 const07 const07 10 10 10 Y 128 0 63
-def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
def test t5 t5 const08 const08 253 19 19 N 1 0 8
-def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
def test t5 t5 const09 const09 12 19 19 Y 128 0 63
-def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
def test t5 t5 const10 const10 3 10 9 N 32769 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
@@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
def test t5 t5 param13 param13 246 67 0 Y 0 30 63
-def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8
-def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
const01 8
param01 8
const02 8.0
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 506a76579ae..699d81d4cef 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -930,7 +930,7 @@ Variable_name Value
Qcache_queries_in_cache 0
show status like "Qcache_inserts";
Variable_name Value
-Qcache_inserts 19
+Qcache_inserts 18
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 6
@@ -943,7 +943,7 @@ Variable_name Value
Qcache_queries_in_cache 1
show status like "Qcache_inserts";
Variable_name Value
-Qcache_inserts 20
+Qcache_inserts 19
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 7
@@ -1007,6 +1007,93 @@ abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab
zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba
flush query cache;
drop table t1, t2;
+flush status;
+CREATE TABLE t1 (
+`date` datetime NOT NULL default '0000-00-00 00:00:00',
+KEY `date` (`date`)
+) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('20050326');
+INSERT INTO t1 VALUES ('20050325');
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0';
+COUNT(*)
+0
+Warnings:
+Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1
+Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 0:0:0';
+COUNT(*)
+0
+Warnings:
+Warning 1292 Incorrect datetime value: '20050328 0:0:0' for column 'date' at row 1
+Warning 1292 Incorrect datetime value: '20050328 0:0:0' for column 'date' at row 1
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0';
+COUNT(*)
+0
+Warnings:
+Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1
+Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1);
+reset query cache;
+flush status;
+select * from (select * from t1) a;
+a
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from (select * from t1) a;
+a
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+insert into t1 values (2);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from (select * from t1) a;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+drop table t1;
create table t1 (a int);
insert into t1 values (1),(2);
CREATE PROCEDURE `p1`()
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index c7d27a8e60d..e8e30b3653a 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -549,6 +549,66 @@ select count(*) from t2 where x = 18446744073709551601;
count(*)
0
drop table t1,t2;
+create table t1 (x bigint unsigned not null primary key) engine=innodb;
+insert into t1(x) values (0xfffffffffffffff0);
+insert into t1(x) values (0xfffffffffffffff1);
+select * from t1;
+x
+18446744073709551600
+18446744073709551601
+select count(*) from t1 where x>0;
+count(*)
+2
+select count(*) from t1 where x=0;
+count(*)
+0
+select count(*) from t1 where x<0;
+count(*)
+0
+select count(*) from t1 where x < -16;
+count(*)
+0
+select count(*) from t1 where x = -16;
+count(*)
+0
+select count(*) from t1 where x > -16;
+count(*)
+2
+select count(*) from t1 where x = 18446744073709551601;
+count(*)
+1
+drop table t1;
+create table t1 (a bigint unsigned);
+create index t1i on t1(a);
+insert into t1 select 18446744073709551615;
+insert into t1 select 18446744073709551614;
+explain select * from t1 where a <> -1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index
+select * from t1 where a <> -1;
+a
+18446744073709551614
+18446744073709551615
+explain select * from t1 where a > -1 or a < -1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index
+select * from t1 where a > -1 or a < -1;
+a
+18446744073709551614
+18446744073709551615
+explain select * from t1 where a > -1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index
+select * from t1 where a > -1;
+a
+18446744073709551614
+18446744073709551615
+explain select * from t1 where a < -1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+select * from t1 where a < -1;
+a
+drop table t1;
set names latin1;
create table t1 (a char(10), b text, key (a)) character set latin1;
INSERT INTO t1 (a) VALUES
@@ -660,3 +720,51 @@ id status
59 C
60 C
DROP TABLE t1;
+CREATE TABLE t1 (a int, b int, primary key(a,b));
+INSERT INTO t1 VALUES
+(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3);
+CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3;
+EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+EXPLAIN SELECT a,b FROM t1 WHERE a < 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+EXPLAIN SELECT a,b FROM v1 WHERE a < 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+SELECT a,b FROM t1 WHERE a < 2 and b=3;
+a b
+1 3
+SELECT a,b FROM v1 WHERE a < 2 and b=3;
+a b
+1 3
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name));
+INSERT INTO t1 VALUES ('Betty'), ('Anna');
+SELECT * FROM t1;
+name
+Anna
+Betty
+DELETE FROM t1 WHERE name NOT LIKE 'A%a';
+SELECT * FROM t1;
+name
+Anna
+DROP TABLE t1;
+CREATE TABLE t1 (a int, KEY idx(a));
+INSERT INTO t1 VALUES (NULL), (1), (2), (3);
+SELECT * FROM t1;
+a
+NULL
+1
+2
+3
+DELETE FROM t1 WHERE NOT(a <=> 2);
+SELECT * FROM t1;
+a
+2
+DROP TABLE t1;
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
index 866edb45cbb..b112a51a145 100644
--- a/mysql-test/r/rpl_deadlock.result
+++ b/mysql-test/r/rpl_deadlock.result
@@ -84,4 +84,4 @@ a
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 18911 # # master-bin.000001 Yes Yes 0 0 18911 # None 0 No #
-drop table t1,t2;
+drop table t1,t2,t3,t4;
diff --git a/mysql-test/r/rpl_innodb.result b/mysql-test/r/rpl_innodb.result
new file mode 100644
index 00000000000..ebf1d79c4d0
--- /dev/null
+++ b/mysql-test/r/rpl_innodb.result
@@ -0,0 +1,37 @@
+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 t4 (
+id INT(5) unsigned NOT NULL auto_increment,
+name varchar(15) NOT NULL default '',
+number varchar(35) NOT NULL default 'default',
+PRIMARY KEY (id),
+UNIQUE KEY unique_rec (name,number)
+) ENGINE=InnoDB;
+LOAD DATA
+INFILE '../../std_data/loaddata_pair.dat'
+REPLACE INTO TABLE t4
+(name,number);
+SELECT * FROM t4;
+id name number
+1 XXX 12345
+2 XXY 12345
+SELECT * FROM t4;
+id name number
+1 XXX 12345
+2 XXY 12345
+LOAD DATA
+INFILE '../../std_data/loaddata_pair.dat'
+REPLACE INTO TABLE t4
+(name,number);
+SELECT * FROM t4;
+id name number
+3 XXX 12345
+4 XXY 12345
+SELECT * FROM t4;
+id name number
+3 XXX 12345
+4 XXY 12345
diff --git a/mysql-test/r/rpl_multi_update3.result b/mysql-test/r/rpl_multi_update3.result
new file mode 100644
index 00000000000..1b757b1400c
--- /dev/null
+++ b/mysql-test/r/rpl_multi_update3.result
@@ -0,0 +1,124 @@
+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;
+
+-------- Test for BUG#9361 --------
+CREATE TABLE t1 (
+a int unsigned not null auto_increment primary key,
+b int unsigned
+) ENGINE=MyISAM;
+CREATE TABLE t2 (
+a int unsigned not null auto_increment primary key,
+b int unsigned
+) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (NULL, 0);
+INSERT INTO t1 SELECT NULL, 0 FROM t1;
+INSERT INTO t2 VALUES (NULL, 0), (NULL,1);
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 0
+2 1
+UPDATE t2, (SELECT a FROM t1) AS t SET t2.b = t.a+5 ;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 6
+2 6
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 6
+2 6
+drop table t1,t2;
+
+-------- Test 1 for BUG#9361 --------
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1 (
+a1 char(30),
+a2 int,
+a3 int,
+a4 char(30),
+a5 char(30)
+);
+CREATE TABLE t2 (
+b1 int,
+b2 char(30)
+);
+INSERT INTO t1 VALUES ('Yes', 1, NULL, 'foo', 'bar');
+INSERT INTO t2 VALUES (1, 'baz');
+UPDATE t1 a, t2
+SET a.a1 = 'No'
+WHERE a.a2 =
+(SELECT b1
+FROM t2
+WHERE b2 = 'baz')
+AND a.a3 IS NULL
+AND a.a4 = 'foo'
+AND a.a5 = 'bar';
+SELECT * FROM t1;
+a1 a2 a3 a4 a5
+No 1 NULL foo bar
+SELECT * FROM t2;
+b1 b2
+1 baz
+DROP TABLE t1, t2;
+
+-------- Test 2 for BUG#9361 --------
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+CREATE TABLE t1 (
+i INT,
+j INT,
+x INT,
+y INT,
+z INT
+);
+CREATE TABLE t2 (
+i INT,
+k INT,
+x INT,
+y INT,
+z INT
+);
+CREATE TABLE t3 (
+j INT,
+k INT,
+x INT,
+y INT,
+z INT
+);
+INSERT INTO t1 VALUES ( 1, 2,13,14,15);
+INSERT INTO t2 VALUES ( 1, 3,23,24,25);
+INSERT INTO t3 VALUES ( 2, 3, 1,34,35), ( 2, 3, 1,34,36);
+UPDATE t1 AS a
+INNER JOIN t2 AS b
+ON a.i = b.i
+INNER JOIN t3 AS c
+ON a.j = c.j AND b.k = c.k
+SET a.x = b.x,
+a.y = b.y,
+a.z = (
+SELECT sum(z)
+FROM t3
+WHERE y = 34
+)
+WHERE b.x = 23;
+SELECT * FROM t1;
+i j x y z
+1 2 23 24 71
+DROP TABLE t1, t2, t3;
diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result
index 7b3249d553a..64e09839f1b 100644
--- a/mysql-test/r/rpl_sp.result
+++ b/mysql-test/r/rpl_sp.result
@@ -21,7 +21,7 @@ set b = 8;
insert into t1 values (b);
insert into t1 values (unix_timestamp());
end|
-ERROR HY000: This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
+ERROR HY000: This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
show binlog events from 98|
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # create database if not exists mysqltest1
@@ -84,7 +84,7 @@ not deterministic
reads sql data
select * from mysqltest1.t1
alter procedure foo2 contains sql;
-ERROR HY000: This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
+ERROR HY000: This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
drop table t1;
create table t1 (a int);
create table t2 like t1;
@@ -97,7 +97,7 @@ grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1;
create procedure foo4()
deterministic
insert into t1 values (10);
-ERROR HY000: You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
+ERROR HY000: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)
set global log_bin_trust_routine_creators=1;
create procedure foo4()
deterministic
@@ -109,7 +109,7 @@ call foo4();
Got one of the listed errors
show warnings;
Level Code Message
-Warning 1417 A routine failed and is declared to modify data and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
+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;
Level Code Message
@@ -117,7 +117,7 @@ call foo4();
Got one of the listed errors
show warnings;
Level Code Message
-Warning 1417 A routine failed and is declared to modify data and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
+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();
show warnings;
diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result
deleted file mode 100644
index 2663fffe4d4..00000000000
--- a/mysql-test/r/rpl_trunc_binlog.result
+++ /dev/null
@@ -1,17 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-stop slave;
-flush logs;
-create table t1 (a int) engine=bdb;
-reset slave;
-start slave;
-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_PORT 1 master-bin.000002 4 # # master-bin.000002 Yes Yes 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. A probable cause is that the master died while writing the transaction to its binary log. 0 4 # None 0 No #
-select * from t1;
-a
-drop table t1;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index bd2825822a1..d327b491ebf 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2073,7 +2073,7 @@ INSERT INTO t1 (pseudo) VALUES ('test1');
SELECT 1 as rnd1 from t1 where rand() > 2;
rnd1
DROP TABLE t1;
-CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp(14) NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM;
+CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM;
INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL);
CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35);
@@ -2423,12 +2423,130 @@ ERROR HY000: Incorrect usage of ALL and DISTINCT
select distinct all * from t1;
ERROR HY000: Incorrect usage of ALL and DISTINCT
drop table t1;
+CREATE TABLE t1 (
+kunde_intern_id int(10) unsigned NOT NULL default '0',
+kunde_id int(10) unsigned NOT NULL default '0',
+FK_firma_id int(10) unsigned NOT NULL default '0',
+aktuell enum('Ja','Nein') NOT NULL default 'Ja',
+vorname varchar(128) NOT NULL default '',
+nachname varchar(128) NOT NULL default '',
+geloescht enum('Ja','Nein') NOT NULL default 'Nein',
+firma varchar(128) NOT NULL default ''
+);
+INSERT INTO t1 VALUES
+(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
+(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
+SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
+WHERE
+(
+(
+( '' != '' AND firma LIKE CONCAT('%', '', '%'))
+OR
+(vorname LIKE CONCAT('%', 'Vorname1', '%') AND
+nachname LIKE CONCAT('%', '1Nachname', '%') AND
+'Vorname1' != '' AND 'xxxx' != '')
+)
+AND
+(
+aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
+)
+)
+;
+kunde_id FK_firma_id aktuell vorname nachname geloescht
+SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
+geloescht FROM t1
+WHERE
+(
+(
+aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
+)
+AND
+(
+( '' != '' AND firma LIKE CONCAT('%', '', '%') )
+OR
+( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
+nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
+'xxxx' != '')
+)
+)
+;
+kunde_id FK_firma_id aktuell vorname nachname geloescht
+SELECT COUNT(*) FROM t1 WHERE
+( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
+AND FK_firma_id = 2;
+COUNT(*)
+0
+drop table t1;
CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b));
INSERT INTO t1 VALUES (0x8000000000000000);
SELECT b FROM t1 WHERE b=0x8000000000000000;
b
9223372036854775808
DROP TABLE t1;
+CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL);
+CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL);
+INSERT INTO `t2` VALUES (0,'READ');
+CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL);
+INSERT INTO `t3` VALUES (1,'fs');
+select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0);
+id name gid uid ident level
+1 fs NULL NULL 0 READ
+drop table t1,t2,t3;
+CREATE TABLE t1 ( city char(30) );
+INSERT INTO t1 VALUES ('London');
+INSERT INTO t1 VALUES ('Paris');
+SELECT * FROM t1 WHERE city='London';
+city
+London
+SELECT * FROM t1 WHERE city='london';
+city
+London
+EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
+SELECT * FROM t1 WHERE city='London' AND city='london';
+city
+London
+EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
+SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
+city
+London
+DROP TABLE t1;
+create table t1 (a int(11) unsigned, b int(11) unsigned);
+insert into t1 values (1,0), (1,1), (1,2);
+select a-b from t1 order by 1;
+a-b
+0
+1
+18446744073709551615
+select a-b , (a-b < 0) from t1 order by 1;
+a-b (a-b < 0)
+0 0
+1 0
+18446744073709551615 0
+select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
+d (a-b >= 0) b
+1 1 0
+0 1 1
+18446744073709551615 1 2
+select cast((a - b) as unsigned) from t1 order by 1;
+cast((a - b) as unsigned)
+0
+1
+18446744073709551615
+drop table t1;
+create table t1 (a int(11));
+select all all * from t1;
+a
+select distinct distinct * from t1;
+a
+select all distinct * from t1;
+ERROR HY000: Incorrect usage of ALL and DISTINCT
+select distinct all * from t1;
+ERROR HY000: Incorrect usage of ALL and DISTINCT
+drop table t1;
CREATE TABLE t1 (
K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '',
K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000',
@@ -2573,115 +2691,6 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5
1 SIMPLE t2 ref a a 23 test.t1.a 2
DROP TABLE t1, t2;
-CREATE TABLE t1 ( city char(30) );
-INSERT INTO t1 VALUES ('London');
-INSERT INTO t1 VALUES ('Paris');
-SELECT * FROM t1 WHERE city='London';
-city
-London
-SELECT * FROM t1 WHERE city='london';
-city
-London
-EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london';
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
-SELECT * FROM t1 WHERE city='London' AND city='london';
-city
-London
-EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
-SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
-city
-London
-DROP TABLE t1;
-create table t1 (a int(11) unsigned, b int(11) unsigned);
-insert into t1 values (1,0), (1,1), (1,2);
-select a-b from t1 order by 1;
-a-b
-0
-1
-18446744073709551615
-select a-b , (a-b < 0) from t1 order by 1;
-a-b (a-b < 0)
-0 0
-1 0
-18446744073709551615 0
-select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
-d (a-b >= 0) b
-1 1 0
-0 1 1
-18446744073709551615 1 2
-select cast((a - b) as unsigned) from t1 order by 1;
-cast((a - b) as unsigned)
-0
-1
-18446744073709551615
-drop table t1;
-create table t1 (a int(11));
-select all all * from t1;
-a
-select distinct distinct * from t1;
-a
-select all distinct * from t1;
-ERROR HY000: Incorrect usage of ALL and DISTINCT
-select distinct all * from t1;
-ERROR HY000: Incorrect usage of ALL and DISTINCT
-drop table t1;
-CREATE TABLE t1 (
-kunde_intern_id int(10) unsigned NOT NULL default '0',
-kunde_id int(10) unsigned NOT NULL default '0',
-FK_firma_id int(10) unsigned NOT NULL default '0',
-aktuell enum('Ja','Nein') NOT NULL default 'Ja',
-vorname varchar(128) NOT NULL default '',
-nachname varchar(128) NOT NULL default '',
-geloescht enum('Ja','Nein') NOT NULL default 'Nein',
-firma varchar(128) NOT NULL default ''
-);
-INSERT INTO t1 VALUES
-(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
-(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
-SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
-WHERE
-(
-(
-( '' != '' AND firma LIKE CONCAT('%', '', '%'))
-OR
-(vorname LIKE CONCAT('%', 'Vorname1', '%') AND
-nachname LIKE CONCAT('%', '1Nachname', '%') AND
-'Vorname1' != '' AND 'xxxx' != '')
-)
-AND
-(
-aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
-)
-)
-;
-kunde_id FK_firma_id aktuell vorname nachname geloescht
-SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
-geloescht FROM t1
-WHERE
-(
-(
-aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
-)
-AND
-(
-( '' != '' AND firma LIKE CONCAT('%', '', '%') )
-OR
-( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
-nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
-'xxxx' != '')
-)
-)
-;
-kunde_id FK_firma_id aktuell vorname nachname geloescht
-SELECT COUNT(*) FROM t1 WHERE
-( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
-AND FK_firma_id = 2;
-COUNT(*)
-0
-drop table t1;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
@@ -2702,3 +2711,49 @@ 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 (
+acct_id int(11) NOT NULL default '0',
+profile_id smallint(6) default NULL,
+UNIQUE KEY t1$acct_id (acct_id),
+KEY t1$profile_id (profile_id)
+);
+INSERT INTO t1 VALUES (132,17),(133,18);
+CREATE TABLE t2 (
+profile_id smallint(6) default NULL,
+queue_id int(11) default NULL,
+seq int(11) default NULL,
+KEY t2$queue_id (queue_id)
+);
+INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1);
+CREATE TABLE t3 (
+id int(11) NOT NULL default '0',
+qtype int(11) default NULL,
+seq int(11) default NULL,
+warn_lvl int(11) default NULL,
+crit_lvl int(11) default NULL,
+rr1 tinyint(4) NOT NULL default '0',
+rr2 int(11) default NULL,
+default_queue tinyint(4) NOT NULL default '0',
+KEY t3$qtype (qtype),
+KEY t3$id (id)
+);
+INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0),
+(36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0);
+SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q
+WHERE
+(pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND
+(pq.queue_id = q.id) AND (q.rr1 <> 1);
+COUNT(*)
+4
+drop table t1,t2,t3;
+create table t1 (f1 int);
+insert into t1 values (1),(NULL);
+create table t2 (f2 int, f3 int, f4 int);
+create index idx1 on t2 (f4);
+insert into t2 values (1,2,3),(2,4,6);
+select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3)
+from t2 C where A.f4 = C.f4) or A.f3 IS NULL;
+f2
+1
+NULL
+drop table t1,t2;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index dd07e0ba755..f1c536ed1da 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -267,9 +267,9 @@ drop table t1;
create table t1 (c decimal(3,3), d double(3,3), f float(3,3));
show columns from t1;
Field Type Null Key Default Extra
-c decimal(4,3) YES NULL
-d double(4,3) YES NULL
-f float(4,3) YES NULL
+c decimal(3,3) YES NULL
+d double(3,3) YES NULL
+f float(3,3) YES NULL
drop table t1;
SET @old_sql_mode= @@sql_mode, sql_mode= '';
SET @old_sql_quote_show_create= @@sql_quote_show_create, sql_quote_show_create= OFF;
@@ -497,3 +497,18 @@ def STATISTICS COMMENT Comment 253 16 0 Y 0 0 63
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 field1 A 0 1000 NULL BTREE
drop table t1;
+create table t1 (
+c1 int NOT NULL,
+c2 int NOT NULL,
+PRIMARY KEY USING HASH (c1),
+INDEX USING BTREE(c2)
+);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` int(11) NOT NULL,
+ PRIMARY KEY USING HASH (`c1`),
+ KEY `c2` USING BTREE (`c2`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index b6ba737a8ba..13f46e507ba 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1,3 +1,4 @@
+drop table if exists t1, t2;
delete from mysql.proc;
create procedure syntaxerror(t int)|
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
@@ -65,47 +66,6 @@ iterate foo;
end|
ERROR 42000: ITERATE with no matching label: foo
create procedure foo()
-begin
-goto foo;
-end|
-ERROR 42000: GOTO with no matching label: foo
-create procedure foo()
-begin
-begin
-label foo;
-end;
-goto foo;
-end|
-ERROR 42000: GOTO with no matching label: foo
-create procedure foo()
-begin
-goto foo;
-begin
-label foo;
-end;
-end|
-ERROR 42000: GOTO with no matching label: foo
-create procedure foo()
-begin
-begin
-goto foo;
-end;
-begin
-label foo;
-end;
-end|
-ERROR 42000: GOTO with no matching label: foo
-create procedure foo()
-begin
-begin
-label foo;
-end;
-begin
-goto foo;
-end;
-end|
-ERROR 42000: GOTO with no matching label: foo
-create procedure foo()
foo: loop
foo: loop
set @x=2;
@@ -308,16 +268,6 @@ declare continue handler for sqlstate '42S99' set x = 1;
declare c cursor for select * from t1;
end|
ERROR 42000: Cursor declaration after handler declaration
-create procedure p()
-begin
-declare continue handler for sqlexception
-begin
-goto L1;
-end;
-select field from t1;
-label L1;
-end|
-ERROR HY000: GOTO is not allowed in a stored procedure handler
drop procedure if exists p|
create procedure p(in x int, inout y int, out z int)
begin
@@ -336,6 +286,19 @@ ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable
call p(42, @tmp_y, 43)|
ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable
drop procedure p|
+create procedure p() begin end|
+lock table t1 read|
+call p()|
+unlock tables|
+drop procedure p|
+lock tables t1 read, mysql.proc write|
+ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
+lock tables mysql.proc write, mysql.user write|
+ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables
+lock tables t1 read, mysql.proc read|
+unlock tables|
+lock tables mysql.proc write|
+unlock tables|
create procedure bug1965()
begin
declare c cursor for select val from t1 order by valname;
@@ -527,7 +490,7 @@ begin
select * from t1;
end|
lock table t1 read|
-call bug9566()|
+alter procedure bug9566 comment 'Some comment'|
ERROR HY000: Table 'proc' was not locked with LOCK TABLES
unlock tables|
drop procedure bug9566|
@@ -654,10 +617,10 @@ flush tables;
return 5;
end|
ERROR 0A000: FLUSH is not allowed in stored procedures
-create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890()
+create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123()
begin
end|
-ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890' is too long
+ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' is too long
drop procedure if exists bug10969|
create procedure bug10969()
begin
@@ -686,3 +649,88 @@ ERROR 0A000: EXECUTE is not allowed in stored procedures
create function f() returns int begin execute stmt;
ERROR 0A000: EXECUTE is not allowed in stored procedures
deallocate prepare stmt;
+create table t1(f1 int);
+create table t2(f1 int);
+CREATE PROCEDURE SP001()
+P1: BEGIN
+DECLARE ENDTABLE INT DEFAULT 0;
+DECLARE TEMP_NUM INT;
+DECLARE TEMP_SUM INT;
+DECLARE C1 CURSOR FOR SELECT F1 FROM t1;
+DECLARE C2 CURSOR FOR SELECT F1 FROM t2;
+DECLARE CONTINUE HANDLER FOR NOT FOUND SET ENDTABLE = 1;
+SET ENDTABLE=0;
+SET TEMP_SUM=0;
+SET TEMP_NUM=0;
+OPEN C1;
+FETCH C1 INTO TEMP_NUM;
+WHILE ENDTABLE = 0 DO
+SET TEMP_SUM=TEMP_NUM+TEMP_SUM;
+FETCH C1 INTO TEMP_NUM;
+END WHILE;
+SELECT TEMP_SUM;
+CLOSE C1;
+CLOSE C1;
+SELECT 'end of proc';
+END P1|
+call SP001();
+TEMP_SUM
+0
+drop procedure SP001;
+drop table t1, t2;
+drop function if exists bug11394|
+drop function if exists bug11394_1|
+drop function if exists bug11394_2|
+drop procedure if exists bug11394|
+create function bug11394(i int) returns int
+begin
+if i <= 0 then
+return 0;
+else
+return (i in (100, 200, bug11394(i-1), 400));
+end if;
+end|
+select bug11394(2)|
+ERROR HY000: Recursive stored routines are not allowed.
+drop function bug11394|
+create function bug11394_1(i int) returns int
+begin
+if i <= 0 then
+return 0;
+else
+return (select bug11394_1(i-1));
+end if;
+end|
+select bug11394_1(2)|
+ERROR HY000: Recursive stored routines are not allowed.
+drop function bug11394_1|
+create function bug11394_2(i int) returns int return i|
+select bug11394_2(bug11394_2(10))|
+bug11394_2(bug11394_2(10))
+10
+drop function bug11394_2|
+create procedure bug11394(i int, j int)
+begin
+if i > 0 then
+call bug11394(i - 1,(select 1));
+end if;
+end|
+call bug11394(2, 1)|
+ERROR HY000: Recursive stored routines are not allowed.
+drop procedure bug11394|
+drop function if exists bug11834_1;
+drop function if exists bug11834_2;
+create function bug11834_1() returns int return 10;
+create function bug11834_2() returns int return bug11834_1();
+prepare stmt from "select bug11834_2()";
+execute stmt;
+bug11834_2()
+10
+execute stmt;
+bug11834_2()
+10
+drop function bug11834_1;
+execute stmt;
+ERROR 42000: FUNCTION test.bug11834_1 does not exist
+deallocate prepare stmt;
+drop function bug11834_2;
diff --git a/mysql-test/r/sp-goto.result b/mysql-test/r/sp-goto.result
new file mode 100644
index 00000000000..ca560f62318
--- /dev/null
+++ b/mysql-test/r/sp-goto.result
@@ -0,0 +1,205 @@
+drop table if exists t1;
+create table t1 (
+id char(16) not null default '',
+data int not null
+);
+drop procedure if exists goto1//
+create procedure goto1()
+begin
+declare y int;
+label a;
+select * from t1;
+select count(*) into y from t1;
+if y > 2 then
+goto b;
+end if;
+insert into t1 values ("j", y);
+goto a;
+label b;
+end//
+call goto1()//
+id data
+id data
+j 0
+id data
+j 0
+j 1
+id data
+j 0
+j 1
+j 2
+drop procedure goto1//
+drop procedure if exists goto2//
+create procedure goto2(a int)
+begin
+declare x int default 0;
+declare continue handler for sqlstate '42S98' set x = 1;
+label a;
+select * from t1;
+b:
+while x < 2 do
+begin
+declare continue handler for sqlstate '42S99' set x = 2;
+if a = 0 then
+set x = x + 1;
+iterate b;
+elseif a = 1 then
+leave b;
+elseif a = 2 then
+set a = 1;
+goto a;
+end if;
+end;
+end while b;
+select * from t1;
+end//
+call goto2(0)//
+id data
+j 0
+j 1
+j 2
+id data
+j 0
+j 1
+j 2
+call goto2(1)//
+id data
+j 0
+j 1
+j 2
+id data
+j 0
+j 1
+j 2
+call goto2(2)//
+id data
+j 0
+j 1
+j 2
+id data
+j 0
+j 1
+j 2
+id data
+j 0
+j 1
+j 2
+drop procedure goto2//
+delete from t1//
+drop procedure if exists goto3//
+create procedure goto3()
+begin
+label L1;
+begin
+end;
+goto L1;
+end//
+drop procedure goto3//
+drop procedure if exists goto4//
+create procedure goto4()
+begin
+begin
+label lab1;
+begin
+goto lab1;
+end;
+end;
+end//
+drop procedure goto4//
+drop procedure if exists goto5//
+create procedure goto5()
+begin
+begin
+begin
+goto lab1;
+end;
+label lab1;
+end;
+end//
+drop procedure goto5//
+drop procedure if exists goto6//
+create procedure goto6()
+begin
+label L1;
+goto L5;
+begin
+label L2;
+goto L1;
+goto L5;
+begin
+label L3;
+goto L1;
+goto L2;
+goto L3;
+goto L4;
+goto L5;
+end;
+goto L2;
+goto L4;
+label L4;
+end;
+label L5;
+goto L1;
+end//
+drop procedure goto6//
+create procedure foo()
+begin
+goto foo;
+end//
+ERROR 42000: GOTO with no matching label: foo
+create procedure foo()
+begin
+begin
+label foo;
+end;
+goto foo;
+end//
+ERROR 42000: GOTO with no matching label: foo
+create procedure foo()
+begin
+goto foo;
+begin
+label foo;
+end;
+end//
+ERROR 42000: GOTO with no matching label: foo
+create procedure foo()
+begin
+begin
+goto foo;
+end;
+begin
+label foo;
+end;
+end//
+ERROR 42000: GOTO with no matching label: foo
+create procedure foo()
+begin
+begin
+label foo;
+end;
+begin
+goto foo;
+end;
+end//
+ERROR 42000: GOTO with no matching label: foo
+create procedure p()
+begin
+declare continue handler for sqlexception
+begin
+goto L1;
+end;
+select field from t1;
+label L1;
+end//
+ERROR HY000: GOTO is not allowed in a stored procedure handler
+drop procedure if exists bug6898//
+create procedure bug6898()
+begin
+goto label1;
+label label1;
+begin end;
+goto label1;
+end//
+drop procedure bug6898//
+drop table t1;
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index ee72fde7324..184978e4a0d 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -1,6 +1,7 @@
use test;
grant usage on *.* to user1@localhost;
flush privileges;
+drop table if exists t1;
drop database if exists db1_secret;
create database db1_secret;
create procedure db1_secret.dummy() begin end;
@@ -194,3 +195,44 @@ use test;
drop database sptest;
delete from mysql.user where user='usera' or user='userb' or user='userc';
delete from mysql.procs_priv where user='usera' or user='userb' or user='userc';
+drop function if exists bug_9503;
+create database mysqltest//
+use mysqltest//
+create table t1 (s1 int)//
+grant select on t1 to user1@localhost//
+create function bug_9503 () returns int sql security invoker begin declare v int;
+select min(s1) into v from t1; return v; end//
+use mysqltest;
+select bug_9503();
+ERROR 42000: execute command denied to user 'user1'@'localhost' for routine 'mysqltest.bug_9503'
+grant execute on function bug_9503 to user1@localhost;
+do 1;
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop function bug_9503;
+use test;
+drop database mysqltest;
+use test;
+select current_user();
+current_user()
+root@localhost
+select user();
+user()
+root@localhost
+create procedure bug7291_0 () sql security invoker select current_user(), user();
+create procedure bug7291_1 () sql security definer call bug7291_0();
+create procedure bug7291_2 () sql security invoker call bug7291_0();
+grant execute on procedure bug7291_0 to user1@localhost;
+grant execute on procedure bug7291_1 to user1@localhost;
+grant execute on procedure bug7291_2 to user1@localhost;
+call bug7291_2();
+current_user() user()
+user1@localhost user1@localhost
+call bug7291_1();
+current_user() user()
+root@localhost user1@localhost
+drop procedure bug7291_1;
+drop procedure bug7291_2;
+drop procedure bug7291_0;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop user user1@localhost;
diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result
index a9d50e6e697..e6b8128c336 100644
--- a/mysql-test/r/sp-threads.result
+++ b/mysql-test/r/sp-threads.result
@@ -55,3 +55,12 @@ call bug11158();
unlock tables;
drop procedure bug11158;
drop table t1, t2;
+drop function if exists bug11554;
+drop view if exists v1;
+create table t1 (i int);
+create function bug11554 () returns int return 1;
+create view v1 as select bug11554() as f;
+insert into t1 (select f from v1);
+drop function bug11554;
+drop table t1;
+drop view v1;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index bf6a4dbf68c..fd63204e32f 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -438,145 +438,6 @@ id data
i 3
delete from t1|
drop procedure i|
-drop procedure if exists goto1|
-create procedure goto1()
-begin
-declare y int;
-label a;
-select * from t1;
-select count(*) into y from t1;
-if y > 2 then
-goto b;
-end if;
-insert into t1 values ("j", y);
-goto a;
-label b;
-end|
-call goto1()|
-id data
-id data
-j 0
-id data
-j 0
-j 1
-id data
-j 0
-j 1
-j 2
-drop procedure goto1|
-drop procedure if exists goto2|
-create procedure goto2(a int)
-begin
-declare x int default 0;
-declare continue handler for sqlstate '42S98' set x = 1;
-label a;
-select * from t1;
-b:
-while x < 2 do
-begin
-declare continue handler for sqlstate '42S99' set x = 2;
-if a = 0 then
-set x = x + 1;
-iterate b;
-elseif a = 1 then
-leave b;
-elseif a = 2 then
-set a = 1;
-goto a;
-end if;
-end;
-end while b;
-select * from t1;
-end|
-call goto2(0)|
-id data
-j 0
-j 1
-j 2
-id data
-j 0
-j 1
-j 2
-call goto2(1)|
-id data
-j 0
-j 1
-j 2
-id data
-j 0
-j 1
-j 2
-call goto2(2)|
-id data
-j 0
-j 1
-j 2
-id data
-j 0
-j 1
-j 2
-id data
-j 0
-j 1
-j 2
-drop procedure goto2|
-delete from t1|
-drop procedure if exists goto3|
-create procedure goto3()
-begin
-label L1;
-begin
-end;
-goto L1;
-end|
-drop procedure goto3|
-drop procedure if exists goto4|
-create procedure goto4()
-begin
-begin
-label lab1;
-begin
-goto lab1;
-end;
-end;
-end|
-drop procedure goto4|
-drop procedure if exists goto5|
-create procedure goto5()
-begin
-begin
-begin
-goto lab1;
-end;
-label lab1;
-end;
-end|
-drop procedure goto5|
-drop procedure if exists goto6|
-create procedure goto6()
-begin
-label L1;
-goto L5;
-begin
-label L2;
-goto L1;
-goto L5;
-begin
-label L3;
-goto L1;
-goto L2;
-goto L3;
-goto L4;
-goto L5;
-end;
-goto L2;
-goto L4;
-label L4;
-end;
-label L5;
-goto L1;
-end|
-drop procedure goto6|
insert into t1 values ("foo", 3), ("bar", 19)|
insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)|
drop procedure if exists sel1|
@@ -1133,8 +994,6 @@ end|
select f5(1)|
f5(1)
1
-select f5(2)|
-ERROR HY000: Table 't1' was not locked with LOCK TABLES
create function f6() returns int
begin
declare n int;
@@ -1229,7 +1088,7 @@ a
select * from v1|
a
3
-select * from v1, v2|
+select * from v1, t1|
ERROR HY000: Table 't1' was not locked with LOCK TABLES
select f4()|
ERROR HY000: Table 't2' was not locked with LOCK TABLES
@@ -1398,60 +1257,6 @@ drop procedure opp|
drop procedure ip|
show procedure status like '%p%'|
Db Name Type Definer Modified Created Security_type Comment
-drop table if exists fib|
-create table fib ( f bigint unsigned not null )|
-drop procedure if exists fib|
-create procedure fib(n int unsigned)
-begin
-if n > 1 then
-begin
-declare x, y bigint unsigned;
-declare c cursor for select f from fib order by f desc limit 2;
-open c;
-fetch c into y;
-fetch c into x;
-close c;
-insert into fib values (x+y);
-call fib(n-1);
-end;
-end if;
-end|
-insert into fib values (0), (1)|
-call fib(3)|
-select * from fib order by f asc|
-f
-0
-1
-1
-2
-delete from fib|
-insert into fib values (0), (1)|
-call fib(20)|
-select * from fib order by f asc|
-f
-0
-1
-1
-2
-3
-5
-8
-13
-21
-34
-55
-89
-144
-233
-377
-610
-987
-1597
-2584
-4181
-6765
-drop table fib|
-drop procedure fib|
drop procedure if exists bar|
create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker
@@ -2508,20 +2313,6 @@ s1
1
drop procedure bug4905|
drop table t3|
-drop function if exists bug6022|
-drop function if exists bug6022|
-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)|
-bug6022(5)
-0
-drop function bug6022|
drop procedure if exists bug6029|
drop procedure if exists bug6029|
create procedure bug6029()
@@ -2866,16 +2657,22 @@ end|
call avg ()|
drop procedure avg|
drop procedure if exists bug6129|
-set @@sql_mode = 'traditional'|
-create procedure bug6129(mode text)
-select @@sql_mode = mode|
-call bug6129(@@sql_mode)|
-@@sql_mode = mode
-1
-set @@sql_mode = ''|
-call bug6129(@@sql_mode)|
-@@sql_mode = mode
-0
+set @old_mode= @@sql_mode;
+set @@sql_mode= "";
+create procedure bug6129()
+select @@sql_mode|
+call bug6129()|
+@@sql_mode
+
+set @@sql_mode= "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO"|
+call bug6129()|
+@@sql_mode
+NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO
+set @@sql_mode= "NO_ZERO_IN_DATE"|
+call bug6129()|
+@@sql_mode
+NO_ZERO_IN_DATE
+set @@sql_mode=@old_mode;
drop procedure bug6129|
drop procedure if exists bug9856|
create procedure bug9856()
@@ -2973,15 +2770,6 @@ select @x|
set global query_cache_size = @qcs1|
delete from t1|
drop function bug9902|
-drop procedure if exists bug6898|
-create procedure bug6898()
-begin
-goto label1;
-label label1;
-begin end;
-goto label1;
-end|
-drop procedure bug6898|
drop function if exists bug9102|
create function bug9102() returns blob return 'a'|
select bug9102()|
@@ -3174,4 +2962,141 @@ a1 a2 a3 data data2 data3
DROP PROCEDURE bug6866;
DROP VIEW tv|
DROP TABLE tt1, tt2, tt3|
+DROP PROCEDURE IF EXISTS bug10136|
+create table t3 ( name char(5) not null primary key, val float not null)|
+insert into t3 values ('aaaaa', 1), ('bbbbb', 2), ('ccccc', 3)|
+create procedure bug10136()
+begin
+declare done int default 3;
+repeat
+select * from t3;
+set done = done - 1;
+until done <= 0 end repeat;
+end|
+call bug10136()|
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+call bug10136()|
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+call bug10136()|
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+name val
+aaaaa 1
+bbbbb 2
+ccccc 3
+drop procedure bug10136|
+drop table t3|
+drop procedure if exists bug11529|
+create procedure bug11529()
+begin
+declare c cursor for select id, data from t1 where data in (10,13);
+open c;
+begin
+declare vid char(16);
+declare vdata int;
+declare exit handler for not found begin end;
+while true do
+fetch c into vid, vdata;
+end while;
+end;
+close c;
+end|
+insert into t1 values
+('Name1', 10),
+('Name2', 11),
+('Name3', 12),
+('Name4', 13),
+('Name5', 14)|
+call bug11529()|
+call bug11529()|
+delete from t1|
+drop procedure bug11529|
+drop procedure if exists bug6063|
+drop procedure if exists bug7088_1|
+drop procedure if exists bug7088_2|
+create procedure bug6063()
+lâbel: begin end|
+call bug6063()|
+show create procedure bug6063|
+Procedure sql_mode Create Procedure
+bug6063 CREATE PROCEDURE `test`.`bug6063`()
+l?bel: begin end
+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|
+Procedure sql_mode Create Procedure
+bug7088_1 CREATE PROCEDURE `test`.`bug7088_1`()
+label1: begin end label1
+show create procedure bug7088_2|
+Procedure sql_mode Create Procedure
+bug7088_2 CREATE PROCEDURE `test`.`bug7088_2`()
+läbel1: begin end
+drop procedure bug6063|
+drop procedure bug7088_1|
+drop procedure bug7088_2|
+drop procedure if exists bug9565_sub|
+drop procedure if exists bug9565|
+create procedure bug9565_sub()
+begin
+select * from t1;
+end|
+create procedure bug9565()
+begin
+insert into t1 values ("one", 1);
+call bug9565_sub();
+end|
+call bug9565()|
+id data
+one 1
+delete from t1|
+drop procedure bug9565_sub|
+drop procedure bug9565|
+drop procedure if exists bug9538|
+create procedure bug9538()
+set @@sort_buffer_size = 1000000|
+set @x = @@sort_buffer_size|
+set @@sort_buffer_size = 2000000|
+select @@sort_buffer_size|
+@@sort_buffer_size
+2000000
+call bug9538()|
+select @@sort_buffer_size|
+@@sort_buffer_size
+1000000
+set @@sort_buffer_size = @x|
+drop procedure bug9538|
drop table t1,t2;
diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result
index c5ba4d15a50..9be5f5bc0d2 100644
--- a/mysql-test/r/sql_mode.result
+++ b/mysql-test/r/sql_mode.result
@@ -120,7 +120,7 @@ create table t1 ( min_num dec(6,6) default .000001);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `min_num` decimal(7,6) default '0.000001'
+ `min_num` decimal(6,6) default '0.000001'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1 ;
set session sql_mode = 'IGNORE_SPACE';
@@ -128,14 +128,14 @@ create table t1 ( min_num dec(6,6) default 0.000001);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `min_num` decimal(7,6) default '0.000001'
+ `min_num` decimal(6,6) default '0.000001'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1 ;
create table t1 ( min_num dec(6,6) default .000001);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `min_num` decimal(7,6) default '0.000001'
+ `min_num` decimal(6,6) default '0.000001'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1 ;
set @@SQL_MODE=NULL;
@@ -402,4 +402,59 @@ a\b a\"b a'\b a'\"b
SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b";
a\b a\'b a"\b a"\'b
a\b a\'b a"\b a"\'b
+set session sql_mode = 'NO_ENGINE_SUBSTITUTION';
+create table t1 (a int) engine=isam;
+ERROR HY000: The 'ISAM' feature is disabled; you need MySQL built with 'ISAM' to have it working
+show create table t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+set session sql_mode = '';
+create table t1 (a int) engine=isam;
+Warnings:
+Warning 1266 Using storage engine MyISAM for table 't1'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+SET @@SQL_MODE='';
+create function `foo` () returns int return 5;
+show create function `foo`;
+Function sql_mode Create Function
+foo CREATE FUNCTION `test`.`foo`() RETURNS int(11)
+return 5
+SET @@SQL_MODE='ANSI_QUOTES';
+show create function `foo`;
+Function sql_mode Create Function
+foo CREATE FUNCTION `test`.`foo`() RETURNS int(11)
+return 5
+drop function `foo`;
+create function `foo` () returns int return 5;
+show create function `foo`;
+Function sql_mode Create Function
+foo ANSI_QUOTES CREATE FUNCTION "test"."foo"() RETURNS int(11)
+return 5
+SET @@SQL_MODE='';
+show create function `foo`;
+Function sql_mode Create Function
+foo ANSI_QUOTES CREATE FUNCTION "test"."foo"() RETURNS int(11)
+return 5
+drop function `foo`;
+SET @@SQL_MODE='';
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select a from t1;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`
+SET @@SQL_MODE='ANSI_QUOTES';
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW "test"."v1" AS select "test"."t1"."a" AS "a" from "test"."t1"
+create view v2 as select a from t2 where a in (select a from v1);
+drop view v2, v1;
+drop table t1, t2;
SET @@SQL_MODE=@OLD_SQL_MODE;
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
index d7ad803b828..adc22cd1ac2 100644
--- a/mysql-test/r/strict.result
+++ b/mysql-test/r/strict.result
@@ -1235,3 +1235,13 @@ create table t1(a varchar(65537));
ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead
create table t1(a varbinary(65537));
ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead
+set @@sql_mode='traditional';
+create table t1(a int, b date not null);
+alter table t1 modify a bigint unsigned not null;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(20) unsigned NOT NULL,
+ `b` date NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 6703147c635..693146c869e 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -1025,7 +1025,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found
2 UNCACHEABLE SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select sql_no_cache (select sql_no_cache ecrypt(_latin1'test') AS `ENCRYPT('test')` from `test`.`t1`) AS `(SELECT ENCRYPT('test') FROM t1)` from `test`.`t1`
+Note 1003 select sql_no_cache (select sql_no_cache encrypt(_latin1'test') AS `ENCRYPT('test')` from `test`.`t1`) AS `(SELECT ENCRYPT('test') FROM t1)` from `test`.`t1`
EXPLAIN EXTENDED SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found
@@ -2816,3 +2816,30 @@ select * from t1;
EMPNUM
E1
DROP TABLE t1,t2;
+CREATE TABLE t1(select_id BIGINT, values_id BIGINT);
+INSERT INTO t1 VALUES (1, 1);
+CREATE TABLE t2 (select_id BIGINT, values_id BIGINT,
+PRIMARY KEY(select_id,values_id));
+INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5);
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+WHERE select_id IN (1, 0));
+values_id
+1
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+WHERE select_id BETWEEN 0 AND 1);
+values_id
+1
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+WHERE select_id = 0 OR select_id = 1);
+values_id
+1
+DROP TABLE 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;
diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result
index 409c9db9f47..277115733d4 100644
--- a/mysql-test/r/system_mysql_db.result
+++ b/mysql-test/r/system_mysql_db.result
@@ -128,7 +128,7 @@ tables_priv CREATE TABLE `tables_priv` (
`Table_name` char(64) collate utf8_bin NOT NULL default '',
`Grantor` char(77) collate utf8_bin NOT NULL default '',
`Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
- `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') character set utf8 NOT NULL default '',
+ `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') character set utf8 NOT NULL default '',
`Column_priv` set('Select','Insert','Update','References') character set utf8 NOT NULL default '',
PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`),
KEY `Grantor` (`Grantor`)
@@ -162,7 +162,7 @@ procs_priv CREATE TABLE `procs_priv` (
show create table proc;
Table Create Table
proc CREATE TABLE `proc` (
- `db` char(64) character set latin1 collate latin1_bin NOT NULL default '',
+ `db` char(64) character set utf8 collate utf8_bin NOT NULL default '',
`name` char(64) NOT NULL default '',
`type` enum('FUNCTION','PROCEDURE') NOT NULL,
`specific_name` char(64) NOT NULL default '',
@@ -173,12 +173,12 @@ proc CREATE TABLE `proc` (
`param_list` blob NOT NULL,
`returns` char(64) NOT NULL default '',
`body` blob NOT NULL,
- `definer` char(77) character set latin1 collate latin1_bin NOT NULL default '',
+ `definer` char(77) character set utf8 collate utf8_bin NOT NULL default '',
`created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`modified` timestamp NOT NULL default '0000-00-00 00:00:00',
`sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL default '',
- `comment` char(64) character set latin1 collate latin1_bin NOT NULL default '',
+ `comment` char(64) character set utf8 collate utf8_bin NOT NULL default '',
PRIMARY KEY (`db`,`name`,`type`)
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Stored Procedures'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Stored Procedures'
show tables;
Tables_in_test
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 996a692d531..efd09ba08fc 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1,6 +1,7 @@
-drop table if exists t1, t2;
+drop table if exists t1, t2, t3;
drop view if exists v1;
drop database if exists mysqltest;
+drop function if exists f1;
create table t1 (i int);
create trigger trg before insert on t1 for each row set @a:=1;
set @a:=0;
@@ -182,6 +183,93 @@ select @log;
@log
(BEFORE_INSERT: new=(id=1, data=5))(BEFORE_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(AFTER_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(BEFORE_INSERT: new=(id=3, data=3))(AFTER_INSERT: new=(id=3, data=3))
drop table t1;
+create table t1 (id int primary key, data varchar(10), fk int);
+create table t2 (event varchar(100));
+create table t3 (id int primary key);
+create trigger t1_ai after insert on t1 for each row
+insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "'"));
+insert into t1 (id, data) values (1, "one"), (2, "two");
+select * from t1;
+id data fk
+1 one NULL
+2 two NULL
+select * from t2;
+event
+INSERT INTO t1 id=1 data='one'
+INSERT INTO t1 id=2 data='two'
+drop trigger t1.t1_ai;
+create trigger t1_bi before insert on t1 for each row
+begin
+if exists (select id from t3 where id=new.fk) then
+insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "' fk=", new.fk));
+else
+insert into t2 values (concat("INSERT INTO t1 FAILED id=", new.id, " data='", new.data, "' fk=", new.fk));
+set new.id= NULL;
+end if;
+end|
+insert into t3 values (1);
+insert into t1 values (4, "four", 1), (5, "five", 2);
+ERROR 23000: Column 'id' cannot be null
+select * from t1;
+id data fk
+1 one NULL
+2 two NULL
+4 four 1
+select * from t2;
+event
+INSERT INTO t1 id=1 data='one'
+INSERT INTO t1 id=2 data='two'
+INSERT INTO t1 id=4 data='four' fk=1
+INSERT INTO t1 FAILED id=5 data='five' fk=2
+drop table t1, t2, t3;
+create table t1 (id int primary key, data varchar(10));
+create table t2 (seq int);
+insert into t2 values (10);
+create function f1 () returns int return (select max(seq) from t2);
+create trigger t1_bi before insert on t1 for each row
+begin
+if new.id > f1() then
+set new.id:= f1();
+end if;
+end|
+insert into t1 values (1, "first");
+insert into t1 values (f1(), "max");
+select * from t1;
+id data
+1 first
+10 max
+drop table t1, t2;
+drop function f1;
+create table t1 (id int primary key, fk_t2 int);
+create table t2 (id int primary key, fk_t3 int);
+create table t3 (id int primary key);
+insert into t1 values (1,1), (2,1), (3,2);
+insert into t2 values (1,1), (2,2);
+insert into t3 values (1), (2);
+create trigger t3_ad after delete on t3 for each row
+delete from t2 where fk_t3=old.id;
+create trigger t2_ad after delete on t2 for each row
+delete from t1 where fk_t2=old.id;
+delete from t3 where id = 1;
+select * from t1 left join (t2 left join t3 on t2.fk_t3 = t3.id) on t1.fk_t2 = t2.id;
+id fk_t2 id fk_t3 id
+3 2 2 2 2
+drop table t1, t2, t3;
+create table t1 (id int primary key, copy int);
+create table t2 (id int primary key, data int);
+insert into t2 values (1,1), (2,2);
+create trigger t1_bi before insert on t1 for each row
+set new.copy= (select data from t2 where id = new.id);
+create trigger t1_bu before update on t1 for each row
+set new.copy= (select data from t2 where id = new.id);
+insert into t1 values (1,3), (2,4), (3,3);
+update t1 set copy= 1 where id = 2;
+select * from t1;
+id copy
+1 1
+2 2
+3 NULL
+drop table t1, t2;
create table t1 (i int);
create trigger trg before insert on t1 for each row set @a:= old.i;
ERROR HY000: There is no OLD row in on INSERT trigger
@@ -209,7 +297,7 @@ drop trigger t1.trg;
ERROR HY000: Trigger does not exist
create view v1 as select * from t1;
create trigger trg before insert on v1 for each row set @a:=1;
-ERROR HY000: Trigger's 'v1' is view or temporary table
+ERROR HY000: 'test.v1' is not BASE TABLE
drop view v1;
drop table t1;
create temporary table t1 (i int);
@@ -482,3 +570,13 @@ i k ts
1 1 0000-00-00 00:00:00
2 2 0000-00-00 00:00:00
drop table t1, t2;
+drop function if exists bug5893;
+create table t1 (col1 int, col2 int);
+insert into t1 values (1, 2);
+create function bug5893 () returns int return 5;
+create trigger t1_bu before update on t1 for each row set new.col1= bug5893();
+drop function bug5893;
+update t1 set col2 = 4;
+ERROR 42000: FUNCTION test.bug5893 does not exist
+drop trigger t1.t1_bu;
+drop table t1;
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
index 4d9bc0c7fe1..4aa8587d6e1 100644
--- a/mysql-test/r/type_bit.result
+++ b/mysql-test/r/type_bit.result
@@ -466,3 +466,90 @@ select a+0 from t1;
a+0
255
drop table t1;
+create table t1 (a bit(7));
+insert into t1 values (120), (0), (111);
+select a+0 from t1 union select a+0 from t1;
+a+0
+120
+0
+111
+select a+0 from t1 union select NULL;
+a+0
+120
+0
+111
+NULL
+select NULL union select a+0 from t1;
+NULL
+NULL
+120
+0
+111
+create table t2 select a from t1 union select a from t1;
+select a+0 from t2;
+a+0
+120
+0
+111
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` bit(7) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1, t2;
+create table t1 (id1 int(11), b1 bit(1));
+create table t2 (id2 int(11), b2 bit(1));
+insert into t1 values (1, 1), (2, 0), (3, 1);
+insert into t2 values (2, 1), (3, 0), (4, 0);
+create algorithm=undefined view v1 as
+select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0
+union
+select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1;
+select * from v1;
+b1+0 b2+0
+0 1
+drop table t1, t2;
+drop view v1;
+create table t1(a bit(4));
+insert into t1(a) values (1), (2), (5), (4), (3);
+insert into t1 select * from t1;
+select a+0 from t1;
+a+0
+1
+2
+5
+4
+3
+1
+2
+5
+4
+3
+drop table t1;
+create table t1 (a1 int(11), b1 bit(2));
+create table t2 (a2 int(11), b2 bit(2));
+insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2);
+insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2);
+select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2;
+a1 a2 b1+0 b2+0
+2 2 0 1
+3 3 1 0
+4 4 2 1
+select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1;
+a1 a2 b1+0 b2+0
+2 2 0 1
+3 3 1 0
+4 4 2 1
+select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2;
+a1 a2 b1+0 b2+0
+1 2 1 1
+3 2 1 1
+2 3 0 0
+1 4 1 1
+3 4 1 1
+4 5 2 2
+select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1;
+sum(a1) b1+0 b2+0
+2 0 0
+4 2 2
+8 1 1
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index 67a011231be..193ed298339 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -703,3 +703,18 @@ select max(i) from t1 where c = '';
max(i)
4
drop table t1;
+create table t1 (a int, b int, c tinyblob, d int, e int);
+alter table t1 add primary key (a,b,c(255),d);
+alter table t1 add key (a,b,d,e);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL default '0',
+ `b` int(11) NOT NULL default '0',
+ `c` tinyblob NOT NULL,
+ `d` int(11) NOT NULL default '0',
+ `e` int(11) default NULL,
+ PRIMARY KEY (`a`,`b`,`c`(255),`d`),
+ KEY `a` (`a`,`b`,`d`,`e`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result
index 93467d1d7da..15f9b839994 100644
--- a/mysql-test/r/type_decimal.result
+++ b/mysql-test/r/type_decimal.result
@@ -476,12 +476,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
CREATE TABLE t1 (a_dec DECIMAL(-1,1));
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,1))' at line 1
CREATE TABLE t1 (a_dec DECIMAL(0,11));
-SHOW CREATE TABLE t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `a_dec` decimal(11,11) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-DROP TABLE t1;
+ERROR 42000: Scale may not be larger than the precision (column 'a_dec').
create table t1(a decimal(7,3));
insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000');
select * from t1;
@@ -699,24 +694,6 @@ select * from t1;
d
1
drop table t1;
-create table t1 (d decimal(64,99));
-show create table t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `d` decimal(64,30) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-insert into t1 values (1);
-select * from t1;
-d
-1.000000000000000000000000000000
-drop table t1;
-create table t1 (d decimal(10,12));
-show create table t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `d` decimal(13,12) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-drop table t1;
create table t1 (d decimal(5));
show create table t1;
Table Create Table
@@ -732,7 +709,7 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (d decimal(66,0));
-ERROR 42000: Incorrect column specifier for column 'd'
+ERROR 42000: Too big precision 66 specified for column 'd'. Maximum is 65.
CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2));
INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result
index b0b3ab147b0..d243985332e 100644
--- a/mysql-test/r/type_float.result
+++ b/mysql-test/r/type_float.result
@@ -103,7 +103,7 @@ select max(a),min(a),avg(a) from t1;
max(a) min(a) avg(a)
1 1 1
drop table t1;
-create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6));
+create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6));
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
f float NULL YES NULL #
@@ -133,17 +133,7 @@ min(a)
-0.010
drop table t1;
create table t1 (a float(200,100), b double(200,100));
-insert t1 values (1.0, 2.0);
-select * from t1;
-a b
-1.000000000000000000000000000000 2.000000000000000000000000000000
-show create table t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `a` float(200,30) default NULL,
- `b` double(200,30) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-drop table t1;
+ERROR 42000: Too big scale 100 specified for column 'a'. Maximum is 30.
create table t1 (c20 char);
insert into t1 values (5000.0);
Warnings:
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index b406dbab82f..c1039189a43 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -876,15 +876,6 @@ SELECT * FROM t1;
f1 f2
9999999999999999999999999999999999.00000000000000000000 0.00
DROP TABLE t1;
-CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB;
-INSERT INTO t1 (GRADE) VALUES (151),(252),(343);
-SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300;
-GRADE
-252
-SELECT GRADE FROM t1 WHERE GRADE= 151;
-GRADE
-151
-DROP TABLE t1;
select abs(10/0);
abs(10/0)
NULL
@@ -928,3 +919,53 @@ select * from t1 where a = -0.00;
a
0.00
drop table t1;
+create table t1 (col1 bigint default -9223372036854775808);
+insert into t1 values (default);
+select * from t1;
+col1
+-9223372036854775808
+drop table t1;
+select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15));
+cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15))
+0.000000000100000
+select ln(14000) c1, convert(ln(14000),decimal(2,3)) c2, cast(ln(14000) as decimal(2,3)) c3;
+c1 c2 c3
+9.5468126085974 9.547 9.547
+create table t1 (sl decimal(70,30));
+ERROR 42000: Too big precision 70 specified for column 'sl'. Maximum is 65.
+create table t1 (sl decimal(32,31));
+ERROR 42000: Too big scale 31 specified for column 'sl'. Maximum is 30.
+create table t1 (sl decimal(0,38));
+ERROR 42000: Too big scale 38 specified for column 'sl'. Maximum is 30.
+create table t1 (sl decimal(0,30));
+ERROR 42000: Scale may not be larger than the precision (column 'sl').
+create table t1 (sl decimal(5, 5));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `sl` decimal(5,5) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (
+f1 decimal unsigned not null default 17.49,
+f2 decimal unsigned not null default 17.68,
+f3 decimal unsigned not null default 99.2,
+f4 decimal unsigned not null default 99.7,
+f5 decimal unsigned not null default 104.49,
+f6 decimal unsigned not null default 199.91,
+f7 decimal unsigned not null default 999.9,
+f8 decimal unsigned not null default 9999.99);
+Warnings:
+Note 1265 Data truncated for column 'f1' at row 1
+Note 1265 Data truncated for column 'f2' at row 1
+Note 1265 Data truncated for column 'f3' at row 1
+Note 1265 Data truncated for column 'f4' at row 1
+Note 1265 Data truncated for column 'f5' at row 1
+Note 1265 Data truncated for column 'f6' at row 1
+Note 1265 Data truncated for column 'f7' at row 1
+Note 1265 Data truncated for column 'f8' at row 1
+insert into t1 (f1) values (1);
+select * from t1;
+f1 f2 f3 f4 f5 f6 f7 f8
+1 18 99 100 104 200 1000 10000
+drop table t1;
diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result
index 9b851d74a12..61ed6bbabf3 100644
--- a/mysql-test/r/type_timestamp.result
+++ b/mysql-test/r/type_timestamp.result
@@ -99,6 +99,14 @@ drop table t1;
create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6),
t8 timestamp(8), t10 timestamp(10), t12 timestamp(12),
t14 timestamp(14));
+Warnings:
+Warning 1287 'TIMESTAMP(2)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(4)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(6)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(8)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(10)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(12)' is deprecated; use 'TIMESTAMP' instead
+Warning 1287 'TIMESTAMP(14)' is deprecated; use 'TIMESTAMP' instead
insert t1 values (0,0,0,0,0,0,0),
("1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59",
"1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59",
diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result
index d83952e118b..b0055346d61 100644
--- a/mysql-test/r/update.result
+++ b/mysql-test/r/update.result
@@ -58,7 +58,7 @@ ushows int(10) unsigned DEFAULT '0' NOT NULL,
clicks int(10) unsigned DEFAULT '0' NOT NULL,
iclicks int(10) unsigned DEFAULT '0' NOT NULL,
uclicks int(10) unsigned DEFAULT '0' NOT NULL,
-ts timestamp(14),
+ts timestamp,
PRIMARY KEY (place_id,ts)
);
INSERT INTO t1 (place_id,shows,ishows,ushows,clicks,iclicks,uclicks,ts)
@@ -75,7 +75,7 @@ client varchar(255) NOT NULL default '',
replyto varchar(255) NOT NULL default '',
subject varchar(100) NOT NULL default '',
timestamp int(10) unsigned NOT NULL default '0',
-tstamp timestamp(14) NOT NULL,
+tstamp timestamp NOT NULL,
status int(3) NOT NULL default '0',
type varchar(15) NOT NULL default '',
assignment int(10) unsigned NOT NULL default '0',
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index 99b4f0529e6..5468508165c 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -504,10 +504,10 @@ t1 CREATE TABLE `t1` (
`c4` double default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
-SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8;
+SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7;
SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE';
Variable_name Value
-myisam_data_pointer_size 8
+myisam_data_pointer_size 7
SET GLOBAL table_cache=-1;
SHOW VARIABLES LIKE 'table_cache';
Variable_name Value
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 84be086ae37..a132279c6bc 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -149,13 +149,13 @@ v5 VIEW
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 2533274790395903 1024 0 NULL # # NULL latin1_swedish_ci NULL
-v1 NULL 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 NULL view
-v3 NULL 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 NULL view
-v5 NULL 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 NULL view
+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
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;
@@ -550,7 +550,7 @@ create table t1 ("a*b" int);
create view v1 as select "a*b" from t1;
show create view v1;
View Create View
-v1 CREATE VIEW "test"."v1" AS select `test`.`t1`.`a*b` AS `a*b` from `test`.`t1`
+v1 CREATE VIEW "test"."v1" AS select "test"."t1"."a*b" AS "a*b" from "test"."t1"
drop view v1;
drop table t1;
set sql_mode=default;
@@ -760,7 +760,7 @@ a b
1 1
show create view v3;
View Create View
-v3 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from `test`.`v1` join `test`.`v2` where (`v1`.`col1` = `v2`.`col1`)
+v3 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from (`test`.`v1` join `test`.`v2`) where (`v1`.`col1` = `v2`.`col1`)
drop view v3, v2, v1;
drop table t2, t1;
create function `f``1` () returns int return 5;
@@ -1561,7 +1561,7 @@ one 1025,2025,3025
two 1050,1050
select col1,group_concat(col2,col3) from v1 group by col1;
col1 group_concat(col2,col3)
-two 1025,2025,3025
+one 1025,2025,3025
two 1050,1050
drop view v1;
drop table t1;
@@ -1726,3 +1726,293 @@ sum(a)
drop procedure p1;
drop view v1;
drop table t1;
+CREATE TABLE t1(a char(2) primary key, b char(2));
+CREATE TABLE t2(a char(2), b char(2), index i(a));
+INSERT INTO t1 VALUES ('a','1'), ('b','2');
+INSERT INTO t2 VALUES ('a','5'), ('a','6'), ('b','5'), ('b','6');
+CREATE VIEW v1 AS
+SELECT t1.b as c, t2.b as d FROM t1,t2 WHERE t1.a=t2.a;
+SELECT d, c FROM v1 ORDER BY d,c;
+d c
+5 1
+5 2
+6 1
+6 2
+DROP VIEW v1;
+DROP TABLE t1, t2;
+create table t1 (s1 int);
+create view v1 as select sum(distinct s1) from t1;
+select * from v1;
+sum(distinct s1)
+NULL
+drop view v1;
+create view v1 as select avg(distinct s1) from t1;
+select * from v1;
+avg(distinct s1)
+NULL
+drop view v1;
+drop table t1;
+create view v1 as select cast(1 as decimal);
+select * from v1;
+cast(1 as decimal)
+1.00
+drop view v1;
+create table t1(f1 int);
+create table t2(f2 int);
+insert into t1 values(1),(2),(3);
+insert into t2 values(1),(2),(3);
+create view v1 as select * from t1,t2 where f1=f2;
+create table t3 (f1 int, f2 int);
+insert into t3 select * from v1 order by 1;
+select * from t3;
+f1 f2
+1 1
+2 2
+3 3
+drop view v1;
+drop table t1,t2,t3;
+create view v1 as select '\\','\\shazam';
+select * from v1;
+\ \shazam
+\ \shazam
+drop view v1;
+create view v1 as select '\'','\shazam';
+select * from v1;
+' shazam
+' shazam
+drop view v1;
+create view v1 as select 'k','K';
+select * from v1;
+k My_exp_K
+k K
+drop view v1;
+create table t1 (s1 int);
+create view v1 as select s1, 's1' from t1;
+select * from v1;
+s1 My_exp_s1
+drop view v1;
+create view v1 as select 's1', s1 from t1;
+select * from v1;
+My_exp_s1 s1
+drop view v1;
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+select * from v1;
+My_exp_1_s1 s1 My_exp_s1
+drop view v1;
+create view v1 as select 1 as My_exp_s1, 's1', s1 from t1;
+select * from v1;
+My_exp_s1 My_exp_1_s1 s1
+drop view v1;
+create view v1 as select 1 as s1, 's1', 's1' from t1;
+select * from v1;
+s1 My_exp_s1 My_exp_1_s1
+drop view v1;
+create view v1 as select 's1', 's1', 1 as s1 from t1;
+select * from v1;
+My_exp_1_s1 My_exp_s1 s1
+drop view v1;
+create view v1 as select s1, 's1', 's1' from t1;
+select * from v1;
+s1 My_exp_s1 My_exp_1_s1
+drop view v1;
+create view v1 as select 's1', 's1', s1 from t1;
+select * from v1;
+My_exp_1_s1 My_exp_s1 s1
+drop view v1;
+create view v1 as select 1 as s1, 's1', s1 from t1;
+ERROR 42S21: Duplicate column name 's1'
+create view v1 as select 's1', s1, 1 as s1 from t1;
+ERROR 42S21: Duplicate column name 's1'
+drop table t1;
+create view v1(k, K) as select 1,2;
+ERROR 42S21: Duplicate column name 'K'
+create view v1 as SELECT TIME_FORMAT(SEC_TO_TIME(3600),'%H:%i') as t;
+select * from v1;
+t
+01:00
+drop view v1;
+create table t1 (a timestamp default now());
+create table t2 (b timestamp default now());
+create view v1 as select a,b,t1.a < now() from t1,t2 where t1.a < now();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b`,(`test`.`t1`.`a` < now()) AS `t1.a < now()` from (`test`.`t1` join `test`.`t2`) where (`test`.`t1`.`a` < now())
+drop view v1;
+drop table t1, t2;
+CREATE TABLE t1 ( a varchar(50) );
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = CURRENT_USER();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = current_user())
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = VERSION();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = version())
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = DATABASE();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = database())
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (col1 time);
+CREATE TABLE t2 (col1 time);
+CREATE VIEW v1 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v2 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+CREATE VIEW v3 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v4 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+CREATE VIEW v5 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v6 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+DROP TABLE t1;
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+Table Op Msg_type Msg_text
+test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
+test.v2 check status OK
+test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s)
+test.v4 check status OK
+test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s)
+test.v6 check status OK
+drop view v1, v2, v3, v4, v5, v6;
+drop table t2;
+CREATE TABLE t1 (col1 time);
+CREATE TABLE t2 (col1 time);
+CREATE TABLE t3 (col1 time);
+create function f1 () returns int return (select max(col1) from t1);
+create function f2 () returns int return (select max(col1) from t2);
+CREATE VIEW v1 AS SELECT f1() FROM t3;
+CREATE VIEW v2 AS SELECT f2() FROM t3;
+CREATE VIEW v3 AS SELECT f1() FROM t3;
+CREATE VIEW v4 AS SELECT f2() FROM t3;
+CREATE VIEW v5 AS SELECT f1() FROM t3;
+CREATE VIEW v6 AS SELECT f2() FROM t3;
+drop function f1;
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+Table Op Msg_type Msg_text
+test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
+test.v2 check status OK
+test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s)
+test.v4 check status OK
+test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s)
+test.v6 check status OK
+create function f1 () returns int return (select max(col1) from t1);
+DROP TABLE t1;
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+Table Op Msg_type Msg_text
+test.v1 check error Table 'test.t1' doesn't exist
+test.v2 check status OK
+test.v3 check error Table 'test.t1' doesn't exist
+test.v4 check status OK
+test.v5 check error Table 'test.t1' doesn't exist
+test.v6 check status OK
+drop function f1;
+drop function f2;
+drop view v1, v2, v3, v4, v5, v6;
+drop table t2,t3;
+create table t1 (f1 date);
+insert into t1 values ('2005-01-01'),('2005-02-02');
+create view v1 as select * from t1;
+select * from v1 where f1='2005.02.02';
+f1
+2005-02-02
+select * from v1 where '2005.02.02'=f1;
+f1
+2005-02-02
+drop view v1;
+drop table t1;
+CREATE VIEW v1 AS SELECT ENCRYPT("dhgdhgd");
+SELECT * FROM v1;
+drop view v1;
+CREATE VIEW v1 AS SELECT SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1);
+SELECT * FROM v1;
+SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1)
+dkjhgd
+drop view v1;
+create table t1 (s1 int);
+create view v1 as select var_samp(s1) from t1;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select var_samp(`test`.`t1`.`s1`) AS `var_samp(s1)` from `test`.`t1`
+drop view v1;
+drop table t1;
+set sql_mode='strict_all_tables';
+CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB;
+CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1;
+CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2;
+INSERT INTO t1 (col1) VALUES(12);
+ERROR HY000: Field 'col2' doesn't have a default value
+INSERT INTO v1 (vcol1) VALUES(12);
+ERROR HY000: Field of view 'test.v1' underlying table doesn't have a default value
+INSERT INTO v2 (vcol1) VALUES(12);
+ERROR HY000: Field of view 'test.v2' underlying table doesn't have a default value
+set sql_mode=default;
+drop view v2,v1;
+drop table t1;
+create table t1 (f1 int);
+insert into t1 values (1);
+create view v1 as select f1 from t1;
+select f1 as alias from v1;
+alias
+1
+drop view v1;
+drop table t1;
+CREATE TABLE t1 (s1 int, s2 int);
+INSERT INTO t1 VALUES (1,2);
+CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1;
+SELECT * FROM v1;
+s1 s2
+2 1
+CREATE PROCEDURE p1 () SELECT * FROM v1;
+CALL p1();
+s1 s2
+2 1
+ALTER VIEW v1 AS SELECT s1 AS s1, s2 AS s2 FROM t1;
+CALL p1();
+s1 s2
+1 2
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1;
+CALL p1();
+s1 s2
+2 1
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+create table t1 (f1 int, f2 int);
+create view v1 as select f1 as f3, f2 as f1 from t1;
+insert into t1 values (1,3),(2,1),(3,2);
+select * from v1 order by f1;
+f3 f1
+2 1
+3 2
+1 3
+drop view v1;
+drop table t1;
+CREATE TABLE t1 (f1 char) ENGINE = innodb;
+INSERT INTO t1 VALUES ('A');
+CREATE VIEW v1 AS SELECT * FROM t1;
+INSERT INTO t1 VALUES('B');
+SELECT * FROM v1;
+f1
+A
+B
+SELECT * FROM t1;
+f1
+A
+B
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 ( bug_table_seq INTEGER NOT NULL);
+CREATE OR REPLACE VIEW v1 AS SELECT * from t1;
+DROP PROCEDURE IF EXISTS p1;
+Warnings:
+Note 1305 PROCEDURE p1 does not exist
+CREATE PROCEDURE p1 ( )
+BEGIN
+DO (SELECT @next := IFNULL(max(bug_table_seq),0) + 1 FROM v1);
+INSERT INTO t1 VALUES (1);
+END //
+CALL p1();
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index df8e2b04f47..b77ee59b3ff 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -284,7 +284,7 @@ create table mysqltest.v3 (b int);
grant select(b) on mysqltest.v3 to mysqltest_1@localhost;
drop table mysqltest.v3;
create view mysqltest.v3 as select b from mysqltest.t2;
-ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3'
+ERROR 42000: create view command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 'v3'
create view v4 as select b+1 from mysqltest.t2;
ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2'
grant create view,update,select on test.* to mysqltest_1@localhost;
diff --git a/mysql-test/std_data/loaddata_pair.dat b/mysql-test/std_data/loaddata_pair.dat
new file mode 100644
index 00000000000..5a4f6b57af8
--- /dev/null
+++ b/mysql-test/std_data/loaddata_pair.dat
@@ -0,0 +1,2 @@
+XXX 12345
+XXY 12345
diff --git a/mysql-test/t/alias.test b/mysql-test/t/alias.test
index 646f077217d..cfa8ec7f18a 100644
--- a/mysql-test/t/alias.test
+++ b/mysql-test/t/alias.test
@@ -30,7 +30,7 @@ CREATE TABLE t1 (
prov_hdl_nr int(11) NOT NULL default '0',
auto_wirknetz varchar(50) default NULL,
auto_billing varchar(50) default NULL,
- touch timestamp(14) NOT NULL,
+ touch timestamp NOT NULL,
kategorie varchar(50) default NULL,
kundentyp varchar(20) NOT NULL default '',
sammel_rech_msisdn varchar(30) NOT NULL default '',
diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test
index 51334fa62bc..a42a42b2a4e 100644
--- a/mysql-test/t/archive.test
+++ b/mysql-test/t/archive.test
@@ -1313,6 +1313,11 @@ INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
SELECT * FROM t2;
OPTIMIZE TABLE t2;
SELECT * FROM t2;
+INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W');
+INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring','');
+INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
+OPTIMIZE TABLE t2 EXTENDED;
+SELECT * FROM t2;
REPAIR TABLE t2;
SELECT * FROM t2;
diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test
index f2cfce9085d..e942333d5fe 100644
--- a/mysql-test/t/case.test
+++ b/mysql-test/t/case.test
@@ -111,6 +111,17 @@ explain extended SELECT
SHOW CREATE TABLE t1;
DROP TABLE t1;
+# Test for BUG#10151
+SELECT 'case+union+test'
+UNION
+SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END;
+
+SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END;
+
+SELECT 'case+union+test'
+UNION
+SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END;
+
#
# Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL
#
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 2722e8572b0..d032c1249df 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -408,6 +408,18 @@ DROP TABLE t1;
SET NAMES latin1;
#
+# Bug#9557 MyISAM utf8 table crash
+#
+CREATE TABLE t1 (
+ a varchar(255) NOT NULL default '',
+ KEY a (a)
+) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci;
+insert into t1 values (0x803d);
+insert into t1 values (0x005b);
+select hex(a) from t1;
+drop table t1;
+
+#
# Conversion from an UCS2 string to a decimal column
#
CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3));
@@ -415,3 +427,17 @@ INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0);
update t1 set b=a;
SELECT * FROM t1;
DROP TABLE t1;
+
+#
+# Bug#9442 Set parameter make query fail if column character set is UCS2
+#
+create table t1 (utext varchar(20) character set ucs2);
+insert into t1 values ("lily");
+insert into t1 values ("river");
+prepare stmt from 'select utext from t1 where utext like ?';
+set @param1='%%';
+execute stmt using @param1;
+execute stmt using @param1;
+select utext from t1 where utext like '%%';
+drop table t1;
+deallocate prepare stmt;
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 343b7c867e7..bcb8ec2ba76 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -748,6 +748,15 @@ select * from t1 where city = 'Durban ';
drop table t1;
#
+# Bug #11819 CREATE TABLE with a SET DEFAULT 0 and UTF8 crashes server.
+#
+--error 1067
+create table t1 (x set('A', 'B') default 0) character set utf8;
+--error 1067
+create table t1 (x enum('A', 'B') default 0) character set utf8;
+
+
+#
# Test for bug #11167: join for utf8 varchar value longer than 255 bytes
#
@@ -776,15 +785,52 @@ INSERT INTO t1 VALUES
(1,'blah','464','aaa','fkc1c9ilc20x0hgae7lx6j09','ERR','ERR Имри.Ðфимим.Ðеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ðд.Д имдимримрад.Ðдимримримрмдиримримримр м.Дадимфшьмримд им.Ðдимимрн имадми','ИМРИ.ÐФИМИМ.ÐЕИМИМРИМДМРИМРМРИРОР',3,'2005-06-01 17:30:43','1234567890'),
(2,'blah','464','aaa','haxpl2ilc20x00bj4tt2m5ti','11','11 g','G',3,'2005-06-02 22:43:10','1234567890');
+--disable_warnings
CREATE TABLE t2 (
`msisdn` varchar(15) NOT NULL default '',
`operator_id` int(11) NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
UNIQUE KEY `PK_user` (`msisdn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+--enable_warnings
INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25');
SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890';
DROP TABLE t1,t2;
+
+#
+# Bug#11591: CHAR column with utf8 does not work properly
+# (more chars than expected)
+#
+create table t1 (a char(20) character set utf8);
+insert into t1 values ('123456'),('андрей');
+alter table t1 modify a char(2) character set utf8;
+select char_length(a), length(a), a from t1 order by a;
+drop table t1;
+
+#
+# Bug#9557 MyISAM utf8 table crash
+#
+CREATE TABLE t1 (
+ a varchar(255) NOT NULL default '',
+ KEY a (a)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
+insert into t1 values (_utf8 0xe880bd);
+insert into t1 values (_utf8 0x5b);
+select hex(a) from t1;
+drop table t1;
+
+#
+# Test for bug #11484: wrong results for a DISTINCT varchar column in uft8.
+#
+
+CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa');
+
+SELECT id FROM t1;
+SELECT DISTINCT id FROM t1;
+SELECT DISTINCT id FROM t1 ORDER BY id;
+
+DROP TABLE t1;
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 9bfe9567d83..c5f96ec4201 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -10,3 +10,4 @@
#
##############################################################################
+sp-goto:GOTO is currently is disabled - will be fixed in the future
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 2acf69dad76..3c4d5dc93da 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -253,9 +253,9 @@ 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);
#
-# bug with many short (< ft_min_word_len) words in boolean search
+# Bug #7858: bug with many short (< ft_min_word_len) words in boolean search
#
-select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode);
+select * from t2 where match name against ('*a*b*c*d*e*f*' in boolean mode);
drop table t1,t2;
#
diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test
index 5c1b4127d8c..3101242613a 100644
--- a/mysql-test/t/fulltext_order_by.test
+++ b/mysql-test/t/fulltext_order_by.test
@@ -54,3 +54,86 @@ SELECT a, MATCH (message) AGAINST ('t* f*' IN BOOLEAN MODE) as rel FROM t1;
SELECT a, MATCH (message) AGAINST ('t* f*' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel,a;
drop table t1;
+# BUG#11869
+CREATE TABLE t1 (
+ id int(11) NOT NULL auto_increment,
+ thread int(11) NOT NULL default '0',
+ beitrag longtext NOT NULL,
+ PRIMARY KEY (id),
+ KEY thread (thread),
+ FULLTEXT KEY beitrag (beitrag)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7923 ;
+
+CREATE TABLE t2 (
+ id int(11) NOT NULL auto_increment,
+ text varchar(100) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY text (text)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ;
+
+CREATE TABLE t3 (
+ id int(11) NOT NULL auto_increment,
+ forum int(11) NOT NULL default '0',
+ betreff varchar(70) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY forum (forum),
+ FULLTEXT KEY betreff (betreff)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ;
+
+--error 1109
+select a.text, b.id, b.betreff
+from
+ t2 a inner join t3 b on a.id = b.forum inner join
+ t1 c on b.id = c.thread
+where
+ match(b.betreff) against ('+abc' in boolean mode)
+group by a.text, b.id, b.betreff
+union
+select a.text, b.id, b.betreff
+from
+ t2 a inner join t3 b on a.id = b.forum inner join
+ t1 c on b.id = c.thread
+where
+ match(c.beitrag) against ('+abc' in boolean mode)
+group by
+ a.text, b.id, b.betreff
+order by
+ match(b.betreff) against ('+abc' in boolean mode) desc;
+
+--error 1109
+select a.text, b.id, b.betreff
+from
+ t2 a inner join t3 b on a.id = b.forum inner join
+ t1 c on b.id = c.thread
+where
+ match(b.betreff) against ('+abc' in boolean mode)
+union
+select a.text, b.id, b.betreff
+from
+ t2 a inner join t3 b on a.id = b.forum inner join
+ t1 c on b.id = c.thread
+where
+ match(c.beitrag) against ('+abc' in boolean mode)
+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
+ t1 c on b.id = c.thread
+where
+ match(b.betreff) against ('+abc' in boolean mode)
+union
+select a.text, b.id, b.betreff
+from
+ t2 a inner join t3 b on a.id = b.forum inner join
+ t1 c on b.id = c.thread
+where
+ match(c.beitrag) against ('+abc' in boolean mode)
+order by
+ match(betreff) against ('+abc' in boolean mode) desc;
+
+drop table t1,t2,t3;
+
diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test
index 93c77daf86e..29c13793b78 100644
--- a/mysql-test/t/func_date_add.test
+++ b/mysql-test/t/func_date_add.test
@@ -11,7 +11,7 @@ CREATE TABLE t1 (
group_id int(10) unsigned DEFAULT '0' NOT NULL,
hits int(10) unsigned DEFAULT '0' NOT NULL,
sessions int(10) unsigned DEFAULT '0' NOT NULL,
- ts timestamp(14),
+ ts timestamp,
PRIMARY KEY (visitor_id,group_id)
)/*! engine=MyISAM */;
INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952);
diff --git a/mysql-test/t/func_des_encrypt.test b/mysql-test/t/func_des_encrypt.test
new file mode 100644
index 00000000000..201a0051c58
--- /dev/null
+++ b/mysql-test/t/func_des_encrypt.test
@@ -0,0 +1,9 @@
+-- source include/have_openssl.inc
+
+# This test can't be in func_encrypt.test, because it requires
+# --des-key-file to not be set.
+
+#
+# Bug #11643: des_encrypt() causes server to die
+#
+select des_encrypt('hello');
diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test
index fe81a814dda..52aca7f9dcb 100644
--- a/mysql-test/t/func_encrypt.test
+++ b/mysql-test/t/func_encrypt.test
@@ -59,6 +59,22 @@ select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("he
select des_decrypt(des_encrypt("hello"),'default_password');
select des_decrypt(des_encrypt("hello",4),'password4');
+# Test use of invalid parameters
+select des_encrypt("hello",10);
+select des_encrypt(NULL);
+select des_encrypt(NULL, 10);
+select des_encrypt(NULL, NULL);
+select des_encrypt(10, NULL);
+select des_encrypt("hello", NULL);
+
+select des_decrypt("hello",10);
+select des_decrypt(NULL);
+select des_decrypt(NULL, 10);
+select des_decrypt(NULL, NULL);
+select des_decrypt(10, NULL);
+select des_decrypt("hello", NULL);
+
+
# Test flush
SET @a=des_decrypt(des_encrypt("hello"));
flush des_key_file;
diff --git a/mysql-test/t/func_encrypt_nossl.test b/mysql-test/t/func_encrypt_nossl.test
new file mode 100644
index 00000000000..95c104ce046
--- /dev/null
+++ b/mysql-test/t/func_encrypt_nossl.test
@@ -0,0 +1,37 @@
+-- source include/not_openssl.inc
+
+#
+# Test output from des_encrypt and des_decrypt when server is
+# compiled without openssl suuport
+#
+select des_encrypt("test", 'akeystr');
+select des_encrypt("test", 1);
+select des_encrypt("test", 9);
+select des_encrypt("test", 100);
+select des_encrypt("test", NULL);
+select des_encrypt(NULL, NULL);
+select des_decrypt("test", 'anotherkeystr');
+select des_decrypt(1, 1);
+select des_decrypt(des_encrypt("test", 'thekey'));
+
+
+#
+# Test default keys
+#
+select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello"));
+select des_decrypt(des_encrypt("hello",4));
+select des_decrypt(des_encrypt("hello",'test'),'test');
+select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password'));
+select des_decrypt(des_encrypt("hello"),'default_password');
+select des_decrypt(des_encrypt("hello",4),'password4');
+
+# Test flush
+SET @a=des_decrypt(des_encrypt("hello"));
+flush des_key_file;
+select @a = des_decrypt(des_encrypt("hello"));
+
+# Test usage of wrong password
+select hex("hello");
+select hex(des_decrypt(des_encrypt("hello",4),'password2'));
+select hex(des_decrypt(des_encrypt("hello","hidden")));
+
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 728f0e2c084..efad2721ae5 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -128,7 +128,7 @@ CREATE TABLE t1 (
program int(10) unsigned default NULL,
bugdesc text,
created datetime default NULL,
- modified timestamp(14) NOT NULL,
+ modified timestamp NOT NULL,
bugstatus int(10) unsigned default NULL,
submitter int(10) unsigned default NULL
) ENGINE=MyISAM;
@@ -529,3 +529,87 @@ DROP TABLE t1, t2;
#
select field(0,NULL,1,0), field("",NULL,"bar",""), field(0.0,NULL,1.0,0.0);
select field(NULL,1,2,NULL), field(NULL,1,2,0);
+
+#
+# Bug #10124: access by integer index with a string key that is not a number
+#
+
+CREATE TABLE t1 (str varchar(20) PRIMARY KEY);
+CREATE TABLE t2 (num int primary key);
+INSERT INTO t1 VALUES ('notnumber');
+INSERT INTO t2 VALUES (0), (1);
+
+SELECT * FROM t1, t2 WHERE num=str;
+SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6);
+
+DROP TABLE t1,t2;
+
+#
+# Bug #11469: NOT NULL optimization wrongly used for arguments of CONCAT_WS
+#
+
+CREATE TABLE t1(
+ id int(11) NOT NULL auto_increment,
+ pc int(11) NOT NULL default '0',
+ title varchar(20) default NULL,
+ PRIMARY KEY (id)
+);
+
+INSERT INTO t1 VALUES
+ (1, 0, 'Main'),
+ (2, 1, 'Toys'),
+ (3, 1, 'Games');
+
+SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1
+ FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id
+ LEFT JOIN t1 AS t3 ON t2.pc=t3.id;
+SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1
+ FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id
+ LEFT JOIN t1 AS t3 ON t2.pc=t3.id
+ WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%';
+
+DROP TABLE t1;
+
+
+CREATE TABLE t1(
+ trackid int(10) unsigned NOT NULL auto_increment,
+ trackname varchar(100) NOT NULL default '',
+ PRIMARY KEY (trackid)
+);
+
+CREATE TABLE t2(
+ artistid int(10) unsigned NOT NULL auto_increment,
+ artistname varchar(100) NOT NULL default '',
+ PRIMARY KEY (artistid)
+);
+
+CREATE TABLE t3(
+ trackid int(10) unsigned NOT NULL,
+ artistid int(10) unsigned NOT NULL,
+ PRIMARY KEY (trackid,artistid)
+);
+
+INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York');
+INSERT INTO t2 VALUES (1, 'Vernon Duke');
+INSERT INTO t3 VALUES (1,1);
+
+SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname
+ FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid
+ LEFT JOIN t2 ON t2.artistid=t3.artistid
+ WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%';
+
+DROP TABLE t1,t2,t3;
+
+#
+# Correct length reporting from substring() (BUG#10269)
+#
+create table t1 (b varchar(5));
+insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde');
+select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1;
+select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t;
+drop table t1;
+
+#
+# Bug #9854 hex() and out of range handling
+#
+select hex(29223372036854775809), hex(-29223372036854775809);
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 6ca29ccded2..66ff460fc61 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -211,7 +211,7 @@ drop table t1;
CREATE TABLE t1 ( start datetime default NULL);
INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00');
-CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL);
+CREATE TABLE t2 ( ctime1 timestamp NOT NULL, ctime2 timestamp NOT NULL);
INSERT INTO t2 VALUES (20021029165106,20021105164731);
CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL);
INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31");
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 34d9a09cba7..bb21873a0c4 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -6,6 +6,7 @@
# Cleanup
--disable_warnings
drop table if exists t1;
+drop database if exists mysqltest;
--enable_warnings
connect (master,localhost,root,,);
@@ -403,3 +404,78 @@ connection root;
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
delete from mysql.user where user=_binary'mysqltest_1';
drop database mysqltest;
+
+#
+# check all new table priveleges
+#
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+SHOW FIELDS FROM mysql.tables_priv;
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+# check view only privileges
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost;
+GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+CREATE USER dummy@localhost;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.dummytable (dummyfield INT);
+CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable;
+GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost;
+GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost;
+SHOW GRANTS FOR dummy@localhost;
+use INFORMATION_SCHEMA;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY
+PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE
+= '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME;
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE mysqltest;
+#
+# Bug #11330: Entry in tables_priv with host = '' causes crash
+#
+connection default;
+use mysql;
+insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select');
+flush privileges;
+delete from tables_priv where host = '' and user = 'mysqltest_1';
+flush privileges;
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index b652df7ecc4..6f1880ae8fb 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -135,7 +135,7 @@ CREATE TABLE t1 (
bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL,
bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL,
creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
- delta_ts timestamp(14),
+ delta_ts timestamp,
short_desc mediumtext,
long_desc mediumtext,
op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL,
@@ -543,6 +543,56 @@ SELECT hostname, COUNT(DISTINCT user_id) as no FROM t1
DROP TABLE t1;
#
+# Test for bug #8614: GROUP BY 'const' with DISTINCT
+#
+
+CREATE TABLE t1 (a int, b int);
+INSERT INTO t1 VALUES (1,2), (1,3);
+SELECT a, b FROM t1 GROUP BY 'const';
+SELECT DISTINCT a, b FROM t1 GROUP BY 'const';
+
+DROP TABLE t1;
+
+#
+# Test for bug #11385: GROUP BY for datetime converted to decimals
+#
+
+CREATE TABLE t1 (id INT, dt DATETIME);
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' );
+SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f;
+
+DROP TABLE t1;
+
+#
+# Test for bug #11295: GROUP BY a BLOB column with COUNT(DISTINCT column1)
+# when the BLOB column takes NULL values
+#
+
+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;
+
+#
+# Test for bug #11414: crash on Windows for a simple GROUP BY query
+#
+
+CREATE TABLE t1 (n int);
+INSERT INTO t1 VALUES (1);
+--disable_ps_protocol
+SELECT n+1 AS n FROM t1 GROUP BY n;
+--enable_ps_protocol
+DROP TABLE t1;
+
+#
# Bug#11211: Ambiguous column reference in GROUP BY.
#
@@ -563,16 +613,5 @@ select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4
group by t1.c1;
show warnings;
-
drop table t1, t2;
-#
-# Test for bug #8614: GROUP BY 'const with DISTINCT
-#
-
-CREATE TABLE t1 (a int, b int);
-INSERT INTO t1 VALUES (1,2), (1,3);
-SELECT a, b FROM t1 GROUP BY 'const';
-SELECT DISTINCT a, b FROM t1 GROUP BY 'const';
-
-DROP TABLE t1;
diff --git a/mysql-test/t/heap_hash.test b/mysql-test/t/heap_hash.test
index 46669dd2b8f..21ac69ef3a1 100644
--- a/mysql-test/t/heap_hash.test
+++ b/mysql-test/t/heap_hash.test
@@ -169,6 +169,8 @@ explain select * from t1 where a='aaac';
explain select * from t1 where a='aaad';
insert into t1 select * from t1;
+# avoid statistics differences between normal and ps-protocol tests
+flush tables;
explain select * from t1 where a='aaaa';
explain select * from t1 where a='aaab';
explain select * from t1 where a='aaac';
diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test
index 5ac91f1f8b1..42175a757c2 100644
--- a/mysql-test/t/index_merge.test
+++ b/mysql-test/t/index_merge.test
@@ -310,7 +310,8 @@ update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
# The next query will not use index i7 in intersection if the OS doesn't
# support file sizes > 2GB. (ha_myisam::ref_length depends on this and index
# scan cost estimates depend on ha_myisam::ref_length)
---replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" 7 # 16 # 18 #
+--replace_column 9 #
+--replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?"
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
from t0 as A, t0 as B
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test
index 5e270c161a2..c10ce3b9688 100644
--- a/mysql-test/t/index_merge_innodb.test
+++ b/mysql-test/t/index_merge_innodb.test
@@ -120,3 +120,14 @@ select count(*) from t1 where
drop table t1,t2;
+# Test for BUG#8441
+create table t1 (
+ id1 int,
+ id2 date ,
+ index idx2 (id1,id2),
+ index idx1 (id2)
+) engine = innodb;
+insert into t1 values(1,'20040101'), (2,'20040102');
+select * from t1 where id1 = 1 and id2= '20040101';
+drop table t1;
+
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index e03bea5899a..7c0624b67fd 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -101,6 +101,12 @@ where COLLATION_NAME like 'latin1%';
# Test for information_schema.ROUTINES &
#
+--disable_warnings
+drop procedure if exists sel2;
+drop function if exists sub1;
+drop function if exists sub2;
+--enable_warnings
+
create function sub1(i int) returns int
return i+1;
delimiter |;
@@ -483,13 +489,14 @@ drop table t1;
# Bug#10261 INFORMATION_SCHEMA.COLUMNS, incomplete result for non root user
#
-create user mysqltest_4@localhost;
+grant select on test.* to mysqltest_4@localhost;
connect (user4,localhost,mysqltest_4,,);
connection user4;
SELECT TABLE_NAME, COLUMN_NAME, PRIVILEGES FROM INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME='TABLE_NAME';
connection default;
delete from mysql.user where user='mysqltest_4';
+delete from mysql.db where user='mysqltest_4';
flush privileges;
#
@@ -510,9 +517,9 @@ grant select on mysqltest.t2 to user2@localhost;
grant select on mysqltest.* to user3@localhost;
grant select on *.* to user4@localhost;
-connect (con1,localhost,user1,,);
-connect (con2,localhost,user2,,);
-connect (con3,localhost,user3,,);
+connect (con1,localhost,user1,,mysqltest);
+connect (con2,localhost,user2,,mysqltest);
+connect (con3,localhost,user3,,mysqltest);
connect (con4,localhost,user4,,);
connection con1;
select * from information_schema.column_privileges;
@@ -546,6 +553,11 @@ drop database mysqltest;
#
# Bug #11055 information_schema: routines.sql_data_access has wrong value
#
+--disable_warnings
+drop procedure if exists p1;
+drop procedure if exists p2;
+--enable_warnings
+
create procedure p1 () modifies sql data set @a = 5;
create procedure p2 () set @a = 5;
select sql_data_access from information_schema.routines
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 06e73d2d32c..2d0e2a4dd65 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -660,9 +660,9 @@ CREATE TABLE t1 (
cname char(15) NOT NULL default '',
carrier_id smallint(6) NOT NULL default '0',
privacy tinyint(4) NOT NULL default '0',
- last_mod_date timestamp(14) NOT NULL,
+ last_mod_date timestamp NOT NULL,
last_mod_id smallint(6) NOT NULL default '0',
- last_app_date timestamp(14) NOT NULL,
+ last_app_date timestamp NOT NULL,
last_app_id smallint(6) default '-1',
version smallint(6) NOT NULL default '0',
assigned_scps int(11) default '0',
@@ -679,9 +679,9 @@ CREATE TABLE t2 (
cname char(15) NOT NULL default '',
carrier_id smallint(6) NOT NULL default '0',
privacy tinyint(4) NOT NULL default '0',
- last_mod_date timestamp(14) NOT NULL,
+ last_mod_date timestamp NOT NULL,
last_mod_id smallint(6) NOT NULL default '0',
- last_app_date timestamp(14) NOT NULL,
+ last_app_date timestamp NOT NULL,
last_app_id smallint(6) default '-1',
version smallint(6) NOT NULL default '0',
assigned_scps int(11) default '0',
@@ -1381,3 +1381,15 @@ update t1 set a=2 where a=1;
insert into t1 (val) values (1);
select * from t1;
drop table t1;
+#
+# Bug #10465
+#
+
+--disable_warnings
+CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB;
+--enable_warnings
+INSERT INTO t1 (GRADE) VALUES (151),(252),(343);
+SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300;
+SELECT GRADE FROM t1 WHERE GRADE= 151;
+DROP TABLE t1;
+
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 40dc4e20093..92e8c7f1231 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
--enable_warnings
create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL);
@@ -164,3 +164,40 @@ INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1
select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1);
drop table t1;
+#
+# Bug#10886 - Have to restore default values after update ON DUPLICATE KEY
+#
+create table t1 (f1 int);
+create table t2 (ff1 int unique, ff2 int default 1);
+insert into t1 values (1),(1),(2);
+insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1;
+select * from t2;
+drop table t1, t2;
+#
+# BUGS #9728 - 'Decreased functionality in "on duplicate key update"'
+# #8147 - 'a column proclaimed ambigous in INSERT ... SELECT .. ON
+# DUPLICATE'
+#
+create table t1 (a int unique);
+create table t2 (a int, b int);
+create table t3 (c int, d int);
+insert into t1 values (1),(2);
+insert into t2 values (1,2);
+insert into t3 values (1,6),(3,7);
+select * from t1;
+insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b;
+select * from t1;
+insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1;
+select * from t1;
+insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d;
+select * from t1;
+insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10;
+
+#Some error cases
+--error 1052
+insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
+--error 1109
+insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b;
+--error 1109
+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 f5857840588..64a76aafa5e 100644
--- a/mysql-test/t/insert_update.test
+++ b/mysql-test/t/insert_update.test
@@ -1,5 +1,5 @@
--disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B));
@@ -72,11 +72,13 @@ CREATE TABLE t2 (a INT, b INT, c INT, d INT);
# column names deliberately clash with columns in t1 (Bug#8147)
INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1);
INSERT t2 VALUES (2,1,11,2), (7,4,40,2);
-INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100;
+INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100;
SELECT * FROM t1;
INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0;
SELECT * FROM t1;
+--error 1052
INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a);
+INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a);
SELECT *, VALUES(a) FROM t1;
DROP TABLE t1;
DROP TABLE t2;
@@ -89,10 +91,12 @@ create table t1 (a int not null unique) engine=myisam;
insert into t1 values (1),(2);
insert ignore into t1 select 1 on duplicate key update a=2;
select * from t1;
-insert ignore into t1 select a from t1 on duplicate key update a=a+1 ;
+insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ;
select * from t1;
insert into t1 select 1 on duplicate key update a=2;
select * from t1;
---error 1062
+--error 1052
insert into t1 select a from t1 on duplicate key update a=a+1 ;
+--error 1052
+insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ;
drop table t1;
diff --git a/mysql-test/t/lowercase_table2.test b/mysql-test/t/lowercase_table2.test
index 51c6f6b5ac3..f5cf292482e 100644
--- a/mysql-test/t/lowercase_table2.test
+++ b/mysql-test/t/lowercase_table2.test
@@ -10,9 +10,10 @@ show variables like "lower_case_table_names";
enable_query_log;
--disable_warnings
-DROP TABLE IF EXISTS t1,t2,t3;
+DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa;
DROP DATABASE IF EXISTS `TEST_$1`;
DROP DATABASE IF EXISTS `test_$1`;
+DROP DATABASE IF EXISTS mysqltest_LC2;
--enable_warnings
CREATE TABLE T1 (a int);
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index f842b8f4d0b..811875a36f5 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -5,7 +5,7 @@
DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
drop database if exists mysqldump_test_db;
drop database if exists db1;
-drop view if exists v1, v2;
+drop view if exists v1, v2, v3;
--enable_warnings
# XML output
@@ -565,7 +565,6 @@ INSERT INTO t1 VALUES (1),(2),(3);
--exec $MYSQL_DUMP --add-drop-database --skip-comments --databases test
DROP TABLE t1;
-
#
# Bug #10213 mysqldump crashes when dumping VIEWs(on MacOS X)
#
@@ -588,3 +587,125 @@ create view v2 as select * from t2 where a like 'a%' with check option;
drop table t2;
drop view v2;
drop database db1;
+#
+# Bug #9558 mysqldump --no-data db t1 t2 format still dumps data
+#
+
+CREATE DATABASE mysqldump_test_db;
+USE mysqldump_test_db;
+CREATE TABLE t1 ( a INT );
+CREATE TABLE t2 ( a INT );
+INSERT INTO t1 VALUES (1), (2);
+INSERT INTO t2 VALUES (1), (2);
+--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db
+--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2
+--exec $MYSQL_DUMP --skip-comments --skip-create --xml --no-data mysqldump_test_db
+--exec $MYSQL_DUMP --skip-comments --skip-create --xml --no-data mysqldump_test_db t1 t2
+DROP TABLE t1, t2;
+DROP DATABASE mysqldump_test_db;
+
+#
+# Testing with tables and databases that don't exists
+# or contains illegal characters
+# (Bug #9358 mysqldump crashes if tablename starts with \)
+#
+create database mysqldump_test_db;
+use mysqldump_test_db;
+create table t1(a varchar(30) primary key, b int not null);
+create table t2(a varchar(30) primary key, b int not null);
+create table t3(a varchar(30) primary key, b int not null);
+
+--disable_query_log
+select '------ Testing with illegal table names ------' as test_sequence ;
+--enable_query_log
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\d-2-1.sql" 2>&1
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\t1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\t1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\\\t1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\\1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t/1" 2>&1
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1"
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T%1"
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T'1"
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1"
+
+--error 6
+--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_"
+
+--disable_query_log
+select '------ Testing with illegal database names ------' as test_sequence ;
+--enable_query_log
+--error 2
+--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_d 2>&1
+
+--error 2
+--exec $MYSQL_DUMP --compact --skip-comments "mysqld\ump_test_db" 2>&1
+
+drop table t1, t2, t3;
+drop database mysqldump_test_db;
+use test;
+
+#
+# Bug #9657 mysqldump xml ( -x ) does not format NULL fields correctly
+#
+
+create table t1 (a int(10));
+create table t2 (pk int primary key auto_increment,
+a int(10), b varchar(30), c datetime, d blob, e text);
+insert into t1 values (NULL), (10), (20);
+insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thirty");
+--exec $MYSQL_DUMP --skip-comments --xml --no-create-info test
+drop table t1, t2;
+
+#
+# Bug #10927 mysqldump: Can't reload dump with view that consist of other view
+#
+
+create table t1(a int, b int, c varchar(30));
+
+insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three");
+
+create view v3 as
+select * from t1;
+
+create view v1 as
+select * from v3 where b in (1, 2, 3, 4, 5, 6, 7);
+
+create view v2 as
+select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1;
+
+--exec $MYSQL_DUMP test > var/tmp/bug10927.sql
+drop view v1, v2, v3;
+drop table t1;
+--exec $MYSQL test < var/tmp/bug10927.sql
+
+# Without dropping the original tables in between
+--exec $MYSQL_DUMP test > var/tmp/bug10927.sql
+--exec $MYSQL test < var/tmp/bug10927.sql
+show full tables;
+show create view v1;
+select * from v1;
+
+drop view v1, v2, v3;
+drop table t1;
diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test
index 1e5c31da98e..2e5e2293b5c 100644
--- a/mysql-test/t/ndb_alter_table.test
+++ b/mysql-test/t/ndb_alter_table.test
@@ -7,6 +7,13 @@ DROP TABLE IF EXISTS t1;
drop database if exists mysqltest;
--enable_warnings
+connect (con1,localhost,root,,test);
+connect (con2,localhost,root,,test);
+
+connection con2;
+-- sleep 2
+connection con1;
+
#
# Basic test to show that the ALTER TABLE
# is working
@@ -92,10 +99,6 @@ CREATE TABLE t1 (
INSERT INTO t1 VALUES (9410,9412);
-connect (con1,localhost,,,test);
-connect (con2,localhost,,,test);
-
-connection con1;
ALTER TABLE t1 ADD COLUMN c int not null;
select * from t1 order by a;
diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test
index 80f6f3f35d3..c2068329d41 100644
--- a/mysql-test/t/ndb_autodiscover.test
+++ b/mysql-test/t/ndb_autodiscover.test
@@ -494,6 +494,28 @@ select * from t1;
use test;
drop database test_only_ndb_tables;
+#####################################################
+# Test that it's not possible to create tables
+# with same name as NDB internal tables
+# This will also test that it's not possible to create
+# a table with tha same name as a table that can't be
+# discovered( for example a table created via NDBAPI)
+
+# Test disabled since it doesn't work on case insensitive systems
+#--error 1050
+#CREATE TABLE sys.SYSTAB_0 (a int);
+#--error 1105
+#select * from sys.SYSTAB_0;
+
+#CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int);
+#show warnings;
+#--error 1105
+#select * from sys.SYSTAB_0;
+
+#--error 1051
+#drop table sys.SYSTAB_0;
+#drop table IF EXISTS sys.SYSTAB_0;
+
######################################################
# Note! This should always be the last step in this
# file, the table t9 will be used and dropped
diff --git a/mysql-test/t/ndb_insert.test b/mysql-test/t/ndb_insert.test
index f88d33f22f4..68f3817e134 100644
--- a/mysql-test/t/ndb_insert.test
+++ b/mysql-test/t/ndb_insert.test
@@ -434,6 +434,9 @@ SELECT COUNT(*) FROM t1;
# Insert duplicate rows
#
--error 1062
+INSERT INTO t1 VALUES (1,1,1);
+
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -457,7 +460,7 @@ rollback;
#
begin;
---error 1062
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -477,7 +480,7 @@ select count(*) from t1;
#
begin;
---error 1062
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -496,7 +499,7 @@ select count(*) from t1;
#
begin;
---error 1062
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -517,7 +520,7 @@ select count(*) from t1;
#
begin;
---error 1062
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -543,7 +546,7 @@ select count(*) from t1;
#
begin;
---error 1062
+--error 1022
INSERT INTO t1 VALUES
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
@@ -562,7 +565,7 @@ select count(*) from t1;
# Insert duplicate rows using "insert .. select"
#
---error 1062
+--error 1022
insert into t1 select * from t1 where b < 10 order by pk1;
DELETE FROM t1 WHERE pk1=2;
diff --git a/mysql-test/t/ndb_subquery.test b/mysql-test/t/ndb_subquery.test
index 9d3a256a263..095fdbcfa13 100644
--- a/mysql-test/t/ndb_subquery.test
+++ b/mysql-test/t/ndb_subquery.test
@@ -37,3 +37,26 @@ drop table t1;
drop table t2;
# bug#5367
##########
+
+###
+# bug#11205
+create table t1 (p int not null primary key, u int not null) engine=ndb;
+insert into t1 values (1,1),(2,2),(3,3);
+
+create table t2 as
+select t1.*
+from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8
+where t1.u = t2.u
+ and t2.u = t3.u
+ and t3.u = t4.u
+ and t4.u = t5.u
+ and t5.u = t6.u
+ and t6.u = t7.u
+ and t7.u = t8.u;
+
+select * from t2 order by 1;
+
+drop table t1;
+drop table t2;
+
+
diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test
index c75cad0b051..26fcc7463d6 100644
--- a/mysql-test/t/olap.test
+++ b/mysql-test/t/olap.test
@@ -250,3 +250,19 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2
DROP TABLE t1,t2;
+#
+# Tests for bug #11639: ROLLUP over view executed through filesort
+#
+
+CREATE TABLE t1(id int, type char(1));
+INSERT INTO t1 VALUES
+ (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"),
+ (6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C");
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT type FROM t1 GROUP BY type WITH ROLLUP;
+SELECT type FROM v1 GROUP BY type WITH ROLLUP;
+EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP;
+
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 60b77576572..de92c67518e 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -149,7 +149,7 @@ create table t1
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
- c13 date, c14 datetime, c15 timestamp(14), c16 time,
+ c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 bit, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -693,3 +693,138 @@ execute stmt using @offset, @limit, @offset, @limit, @limit;
drop table t1;
deallocate prepare stmt;
+
+#
+# Bug#11060 "Server crashes on calling stored procedure with INSERT SELECT
+# UNION SELECT" aka "Server crashes on re-execution of prepared INSERT ...
+# SELECT with UNION".
+#
+create table t1 (id int);
+prepare stmt from "insert into t1 (id) select id from t1 union select id from t1";
+execute stmt;
+execute stmt;
+deallocate prepare stmt;
+drop table t1;
+#
+# Bug#11458 "Prepared statement with subselects return random data":
+# drop PARAM_TABLE_BIT from the list of tables used by a subquery
+#
+create table t1 (
+ id int(11) unsigned not null primary key auto_increment,
+ partner_id varchar(35) not null,
+ t1_status_id int(10) unsigned
+);
+
+insert into t1 values ("1", "partner1", "10"), ("2", "partner2", "10"),
+ ("3", "partner3", "10"), ("4", "partner4", "10");
+
+create table t2 (
+ id int(11) unsigned not null default '0',
+ t1_line_id int(11) unsigned not null default '0',
+ article_id varchar(20),
+ sequence int(11) not null default '0',
+ primary key (id,t1_line_id)
+);
+
+insert into t2 values ("1", "1", "sup", "0"), ("2", "1", "sup", "1"),
+ ("2", "2", "sup", "2"), ("2", "3", "sup", "3"),
+ ("2", "4", "imp", "4"), ("3", "1", "sup", "0"),
+ ("4", "1", "sup", "0");
+
+create table t3 (
+ id int(11) not null default '0',
+ preceeding_id int(11) not null default '0',
+ primary key (id,preceeding_id)
+);
+
+create table t4 (
+ user_id varchar(50) not null,
+ article_id varchar(20) not null,
+ primary key (user_id,article_id)
+);
+
+insert into t4 values("nicke", "imp");
+
+prepare stmt from
+'select distinct t1.partner_id
+from t1 left join t3 on t1.id = t3.id
+ left join t1 pp on pp.id = t3.preceeding_id
+where
+ exists (
+ select *
+ from t2 as pl_inner
+ where pl_inner.id = t1.id
+ and pl_inner.sequence <= (
+ select min(sequence) from t2 pl_seqnr
+ where pl_seqnr.id = t1.id
+ )
+ and exists (
+ select * from t4
+ where t4.article_id = pl_inner.article_id
+ and t4.user_id = ?
+ )
+ )
+ and t1.id = ?
+group by t1.id
+having count(pp.id) = 0';
+set @user_id = 'nicke';
+set @id = '2';
+execute stmt using @user_id, @id;
+execute stmt using @user_id, @id;
+deallocate prepare stmt;
+drop table t1, t2, t3, t4;
+#
+# Bug#9379: make sure that Item::collation is reset when one sets
+# a parameter marker from a string variable.
+#
+prepare stmt from 'select ?=?';
+set @a='CHRISTINE ';
+set @b='CHRISTINE';
+execute stmt using @a, @b;
+execute stmt using @a, @b;
+set @a=1, @b=2;
+execute stmt using @a, @b;
+set @a='CHRISTINE ';
+set @b='CHRISTINE';
+execute stmt using @a, @b;
+deallocate prepare stmt;
+#
+# Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops
+# replication": check that errouneous queries with placeholders are not
+# allowed
+#
+create table t1 (a int);
+--error 1064
+prepare stmt from "select ??";
+--error 1064
+prepare stmt from "select ?FROM t1";
+--error 1064
+prepare stmt from "select FROM t1 WHERE?=1";
+--error 1064
+prepare stmt from "update t1 set a=a+?WHERE 1";
+--disable_ps_protocol
+--error 1064
+select ?;
+--error 1064
+select ??;
+--error 1064
+select ? from t1;
+--enable_ps_protocol
+drop table t1;
+#
+# Bug#9359 "Prepared statements take snapshot of system vars at PREPARE
+# time"
+#
+prepare stmt from "select @@time_zone";
+execute stmt;
+set @@time_zone:='Japan';
+execute stmt;
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+set transaction isolation level read committed;
+execute stmt;
+set transaction isolation level serializable;
+execute stmt;
+set @@tx_isolation=default;
+execute stmt;
+deallocate prepare stmt;
diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test
index 1c247240eb9..ab133e4c347 100644
--- a/mysql-test/t/ps_1general.test
+++ b/mysql-test/t/ps_1general.test
@@ -307,15 +307,13 @@ prepare stmt4 from ' show index from t2 from test ';
execute stmt4;
prepare stmt4 from ' show table status from test like ''t2%'' ';
# egalize date and time values
---replace_column 12 # 13 # 14 #
---replace_result 2147483647 64424509439
+--replace_column 8 # 12 # 13 # 14 #
# Bug#4288 : prepared statement 'show table status ..', wrong output on execute
execute stmt4;
# try the same with the big table
prepare stmt4 from ' show table status from test like ''t9%'' ';
# egalize date and time values
---replace_column 12 # 13 # 14 #
---replace_result 2147483647 4294967295
+--replace_column 8 # 12 # 13 # 14 #
# Bug#4288
execute stmt4;
prepare stmt4 from ' show status like ''Threads_running'' ';
diff --git a/mysql-test/t/ps_4heap.test b/mysql-test/t/ps_4heap.test
index 1c9346721ab..3ce3bea8265 100644
--- a/mysql-test/t/ps_4heap.test
+++ b/mysql-test/t/ps_4heap.test
@@ -31,7 +31,7 @@ eval create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
- c13 date, c14 datetime, c15 timestamp(14), c16 time,
+ c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 varchar(100), c24 varchar(100),
c25 varchar(100), c26 varchar(100), c27 varchar(100), c28 varchar(100),
diff --git a/mysql-test/t/ps_5merge.test b/mysql-test/t/ps_5merge.test
index 891d1be2c57..7e94ede41d1 100644
--- a/mysql-test/t/ps_5merge.test
+++ b/mysql-test/t/ps_5merge.test
@@ -31,7 +31,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
- c13 date, c14 datetime, c15 timestamp(14), c16 time,
+ c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
@@ -62,7 +62,7 @@ create table t9
c1 tinyint, c2 smallint, c3 mediumint, c4 int,
c5 integer, c6 bigint, c7 float, c8 double,
c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
- c13 date, c14 datetime, c15 timestamp(14), c16 time,
+ c13 date, c14 datetime, c15 timestamp, c16 time,
c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index 88891bd3881..3a0ac08b1ba 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -757,6 +757,50 @@ flush query cache;
drop table t1, t2;
#
+# Query with warning prohibited to query cache (BUG#9414)
+#
+flush status;
+CREATE TABLE t1 (
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ KEY `date` (`date`)
+) ENGINE=MyISAM;
+
+INSERT INTO t1 VALUES ('20050326');
+INSERT INTO t1 VALUES ('20050325');
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0';
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 0:0:0';
+SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0';
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# queries with subquery in the FROM clause (BUG#11522)
+#
+create table t1 (a int);
+insert into t1 values (1);
+reset query cache;
+flush status;
+select * from (select * from t1) a;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from (select * from t1) a;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+insert into t1 values (2);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from (select * from t1) a;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop table t1;
+
+#
# SP cursors and selects with query cache (BUG#9715)
#
create table t1 (a int);
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index a5822602b82..065cef659b8 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -418,6 +418,41 @@ select count(*) from t2 where x > -16;
select count(*) from t2 where x = 18446744073709551601;
drop table t1,t2;
+--disable_warnings
+create table t1 (x bigint unsigned not null primary key) engine=innodb;
+--enable_warnings
+insert into t1(x) values (0xfffffffffffffff0);
+insert into t1(x) values (0xfffffffffffffff1);
+select * from t1;
+select count(*) from t1 where x>0;
+select count(*) from t1 where x=0;
+select count(*) from t1 where x<0;
+select count(*) from t1 where x < -16;
+select count(*) from t1 where x = -16;
+select count(*) from t1 where x > -16;
+select count(*) from t1 where x = 18446744073709551601;
+
+drop table t1;
+
+#
+# Bug #11185 incorrect comparison of unsigned int to signed constant
+#
+create table t1 (a bigint unsigned);
+create index t1i on t1(a);
+insert into t1 select 18446744073709551615;
+insert into t1 select 18446744073709551614;
+
+explain select * from t1 where a <> -1;
+select * from t1 where a <> -1;
+explain select * from t1 where a > -1 or a < -1;
+select * from t1 where a > -1 or a < -1;
+explain select * from t1 where a > -1;
+select * from t1 where a > -1;
+explain select * from t1 where a < -1;
+select * from t1 where a < -1;
+
+drop table t1;
+
#
# Bug #6045: Binary Comparison regression in MySQL 4.1
# Binary searches didn't use a case insensitive index.
@@ -495,3 +530,49 @@ SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B';
SELECT * FROM t1 WHERE status < 'A' OR status > 'B';
DROP TABLE t1;
+
+#
+# Test for bug #10031: range to be used over a view
+#
+
+CREATE TABLE t1 (a int, b int, primary key(a,b));
+
+INSERT INTO t1 VALUES
+ (1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3);
+
+CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3;
+
+EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3;
+EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3;
+
+EXPLAIN SELECT a,b FROM t1 WHERE a < 2;
+EXPLAIN SELECT a,b FROM v1 WHERE a < 2;
+
+SELECT a,b FROM t1 WHERE a < 2 and b=3;
+SELECT a,b FROM v1 WHERE a < 2 and b=3;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# Bug #11853: DELETE statement with a NOT (LIKE/<=>) where condition
+# for an indexed attribute
+#
+
+CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name));
+INSERT INTO t1 VALUES ('Betty'), ('Anna');
+
+SELECT * FROM t1;
+DELETE FROM t1 WHERE name NOT LIKE 'A%a';
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+CREATE TABLE t1 (a int, KEY idx(a));
+INSERT INTO t1 VALUES (NULL), (1), (2), (3);
+
+SELECT * FROM t1;
+DELETE FROM t1 WHERE NOT(a <=> 2);
+SELECT * FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
index 3bcbb1d4567..eb4c5c33714 100644
--- a/mysql-test/t/rpl_deadlock.test
+++ b/mysql-test/t/rpl_deadlock.test
@@ -107,5 +107,5 @@ select * from t2;
show slave status;
connection master;
-drop table t1,t2;
+drop table t1,t2,t3,t4;
sync_slave_with_master;
diff --git a/mysql-test/t/rpl_innodb.test b/mysql-test/t/rpl_innodb.test
new file mode 100644
index 00000000000..b171dced26e
--- /dev/null
+++ b/mysql-test/t/rpl_innodb.test
@@ -0,0 +1,46 @@
+# File for specialities regarding replication from or to InnoDB
+# tables.
+
+source include/master-slave.inc;
+source include/have_innodb.inc;
+
+#
+# Bug#11401: Load data infile 'REPLACE INTO' fails on slave.
+#
+connection master;
+CREATE TABLE t4 (
+ id INT(5) unsigned NOT NULL auto_increment,
+ name varchar(15) NOT NULL default '',
+ number varchar(35) NOT NULL default 'default',
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_rec (name,number)
+) ENGINE=InnoDB;
+
+--disable_warnings
+LOAD DATA
+ INFILE '../../std_data/loaddata_pair.dat'
+ REPLACE INTO TABLE t4
+ (name,number);
+--enable_warnings
+SELECT * FROM t4;
+
+sync_slave_with_master;
+SELECT * FROM t4;
+
+connection master;
+--disable_warnings
+LOAD DATA
+ INFILE '../../std_data/loaddata_pair.dat'
+ REPLACE INTO TABLE t4
+ (name,number);
+--enable_warnings
+SELECT * FROM t4;
+
+sync_slave_with_master;
+SELECT * FROM t4;
+
+connection master;
+--disable_query_log
+DROP TABLE t4;
+--enable_query_log
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test
new file mode 100644
index 00000000000..80b0603eb60
--- /dev/null
+++ b/mysql-test/t/rpl_multi_update3.test
@@ -0,0 +1,159 @@
+source include/master-slave.inc;
+
+##############################################################################
+#
+# Let's verify that multi-update with a subselect does not cause the slave to crash
+# (BUG#10442)
+#
+--disable_query_log
+SELECT '-------- Test for BUG#9361 --------' as "";
+--enable_query_log
+
+CREATE TABLE t1 (
+ a int unsigned not null auto_increment primary key,
+ b int unsigned
+) ENGINE=MyISAM;
+
+CREATE TABLE t2 (
+ a int unsigned not null auto_increment primary key,
+ b int unsigned
+) ENGINE=MyISAM;
+
+INSERT INTO t1 VALUES (NULL, 0);
+INSERT INTO t1 SELECT NULL, 0 FROM t1;
+
+INSERT INTO t2 VALUES (NULL, 0), (NULL,1);
+
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+UPDATE t2, (SELECT a FROM t1) AS t SET t2.b = t.a+5 ;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+sync_slave_with_master;
+connection slave;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+connection master;
+drop table t1,t2;
+
+##############################################################################
+#
+# Test for BUG#9361:
+# Subselects should work inside multi-updates
+#
+--disable_query_log
+SELECT '-------- Test 1 for BUG#9361 --------' as "";
+--enable_query_log
+
+connection master;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1 (
+ a1 char(30),
+ a2 int,
+ a3 int,
+ a4 char(30),
+ a5 char(30)
+);
+
+CREATE TABLE t2 (
+ b1 int,
+ b2 char(30)
+);
+
+# Insert one row per table
+INSERT INTO t1 VALUES ('Yes', 1, NULL, 'foo', 'bar');
+INSERT INTO t2 VALUES (1, 'baz');
+
+# This should update the row in t1
+UPDATE t1 a, t2
+ SET a.a1 = 'No'
+ WHERE a.a2 =
+ (SELECT b1
+ FROM t2
+ WHERE b2 = 'baz')
+ AND a.a3 IS NULL
+ AND a.a4 = 'foo'
+ AND a.a5 = 'bar';
+
+sync_slave_with_master;
+connection slave;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+connection master;
+DROP TABLE t1, t2;
+
+##############################################################################
+#
+# Second test for BUG#9361
+#
+
+--disable_query_log
+SELECT '-------- Test 2 for BUG#9361 --------' as "";
+--enable_query_log
+
+connection master;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+--enable_warnings
+
+CREATE TABLE t1 (
+ i INT,
+ j INT,
+ x INT,
+ y INT,
+ z INT
+);
+
+CREATE TABLE t2 (
+ i INT,
+ k INT,
+ x INT,
+ y INT,
+ z INT
+);
+
+CREATE TABLE t3 (
+ j INT,
+ k INT,
+ x INT,
+ y INT,
+ z INT
+);
+
+INSERT INTO t1 VALUES ( 1, 2,13,14,15);
+INSERT INTO t2 VALUES ( 1, 3,23,24,25);
+INSERT INTO t3 VALUES ( 2, 3, 1,34,35), ( 2, 3, 1,34,36);
+
+UPDATE t1 AS a
+INNER JOIN t2 AS b
+ ON a.i = b.i
+INNER JOIN t3 AS c
+ ON a.j = c.j AND b.k = c.k
+SET a.x = b.x,
+ a.y = b.y,
+ a.z = (
+ SELECT sum(z)
+ FROM t3
+ WHERE y = 34
+ )
+WHERE b.x = 23;
+
+sync_slave_with_master;
+connection slave;
+
+SELECT * FROM t1;
+
+connection master;
+DROP TABLE t1, t2, t3;
diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test
deleted file mode 100644
index eec36532275..00000000000
--- a/mysql-test/t/rpl_trunc_binlog.test
+++ /dev/null
@@ -1,35 +0,0 @@
-# We are testing if a binlog which contains BEGIN but not COMMIT (the
-# master died while writing the transaction to the binlog) triggers a
-# rollback on slave. So we use such a truncated binlog and simulate that
-# the master restarted after this.
-
-source include/master-slave.inc;
-
-connection slave;
-# If we are not supporting transactions in the slave, the unfinished
-# transaction won't cause any error, so we need to skip the test. In the 4.0
-# testsuite, the slave always runs without InnoDB, so we check for BDB.
-source include/have_bdb.inc;
-stop slave;
-
-connection master;
-flush logs;
-system mv -f var/log/master-bin.000001 var/log/master-bin.000002;
-system cp std_data/trunc_binlog.000001 var/log/master-bin.000001;
-
-connection slave;
-
-# truncated binlog contains: BEGIN; INSERT t1 VALUES (1);
-# so let's create the table t1 on slave
-
-create table t1 (a int) engine=bdb;
-reset slave;
-start slave;
-# can't sync_with_master so we must sleep
-sleep 3;
---replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
-show slave status;
-select * from t1;
-drop table t1;
-
diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test
index 714719f5441..c1aee2cb1db 100644
--- a/mysql-test/t/rpl_until.test
+++ b/mysql-test/t/rpl_until.test
@@ -26,6 +26,7 @@ show binlog events;
connection slave;
start slave until master_log_file='master-bin.000001', master_log_pos=319;
sleep 2;
+wait_for_slave_to_stop;
# here table should be still not deleted
select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
@@ -37,13 +38,15 @@ start slave until master_log_file='master-no-such-bin.000001', master_log_pos=29
# again this table should be still not deleted
select * from t1;
sleep 2;
+wait_for_slave_to_stop;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 9 # 23 # 33 #
show slave status;
# try replicate all until second insert to t2;
start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
-sleep 4;
+sleep 2;
+wait_for_slave_to_stop;
select * from t2;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 9 # 23 # 33 #
@@ -59,8 +62,8 @@ stop slave;
# this should stop immediately as we are already there
start slave until master_log_file='master-bin.000001', master_log_pos=776;
-# 2 is not enough when running with valgrind
-real_sleep 4
+sleep 2;
+wait_for_slave_to_stop;
# here the sql slave thread should be stopped
--replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004
--replace_column 1 # 9 # 23 # 33 #
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 2558a3aeaeb..69343524928 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -1789,7 +1789,7 @@ DROP TABLE t1;
# Test of bug with SUM(CASE...)
#
-CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp(14) NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM;
+CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM;
INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL);
CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35);
@@ -1954,7 +1954,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a;
DROP TABLE t1, t2;
-
#
# Test case for bug 7098: substitution of a constant for a string field
#
@@ -1998,6 +1997,64 @@ select distinct all * from t1;
drop table t1;
#
+# Test for BUG#10095
+#
+CREATE TABLE t1 (
+ kunde_intern_id int(10) unsigned NOT NULL default '0',
+ kunde_id int(10) unsigned NOT NULL default '0',
+ FK_firma_id int(10) unsigned NOT NULL default '0',
+ aktuell enum('Ja','Nein') NOT NULL default 'Ja',
+ vorname varchar(128) NOT NULL default '',
+ nachname varchar(128) NOT NULL default '',
+ geloescht enum('Ja','Nein') NOT NULL default 'Nein',
+ firma varchar(128) NOT NULL default ''
+);
+
+INSERT INTO t1 VALUES
+ (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
+ (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
+
+
+SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
+ WHERE
+ (
+ (
+ ( '' != '' AND firma LIKE CONCAT('%', '', '%'))
+ OR
+ (vorname LIKE CONCAT('%', 'Vorname1', '%') AND
+ nachname LIKE CONCAT('%', '1Nachname', '%') AND
+ 'Vorname1' != '' AND 'xxxx' != '')
+ )
+ AND
+ (
+ aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
+ )
+ )
+ ;
+
+SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
+geloescht FROM t1
+ WHERE
+ (
+ (
+ aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
+ )
+ AND
+ (
+ ( '' != '' AND firma LIKE CONCAT('%', '', '%') )
+ OR
+ ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
+nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
+'xxxx' != '')
+ )
+ )
+ ;
+
+SELECT COUNT(*) FROM t1 WHERE
+( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
+AND FK_firma_id = 2;
+
+drop table t1;
#
# Test for Bug#8009, SELECT failed on bigint unsigned when using HEX
@@ -2007,6 +2064,65 @@ CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b));
INSERT INTO t1 VALUES (0x8000000000000000);
SELECT b FROM t1 WHERE b=0x8000000000000000;
DROP TABLE t1;
+
+#
+# IN with outer join condition (BUG#9393)
+#
+CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL);
+
+CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL);
+INSERT INTO `t2` VALUES (0,'READ');
+
+CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL);
+INSERT INTO `t3` VALUES (1,'fs');
+
+select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0);
+
+drop table t1,t2,t3;
+
+#
+# Test case for bug 7098: substitution of a constant for a string field
+#
+
+CREATE TABLE t1 ( city char(30) );
+INSERT INTO t1 VALUES ('London');
+INSERT INTO t1 VALUES ('Paris');
+
+SELECT * FROM t1 WHERE city='London';
+SELECT * FROM t1 WHERE city='london';
+EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london';
+SELECT * FROM t1 WHERE city='London' AND city='london';
+EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
+SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
+
+DROP TABLE t1;
+
+#
+# Bug#7425 inconsistent sort order on unsigned columns result of substraction
+#
+
+create table t1 (a int(11) unsigned, b int(11) unsigned);
+insert into t1 values (1,0), (1,1), (1,2);
+select a-b from t1 order by 1;
+select a-b , (a-b < 0) from t1 order by 1;
+select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
+select cast((a - b) as unsigned) from t1 order by 1;
+drop table t1;
+
+
+#
+# Bug#8733 server accepts malformed query (multiply mentioned distinct)
+#
+create table t1 (a int(11));
+select all all * from t1;
+select distinct distinct * from t1;
+--error 1221
+select all distinct * from t1;
+--error 1221
+select distinct all * from t1;
+drop table t1;
+
+#
# Test for bug #6474
#
@@ -2154,108 +2270,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a;
DROP TABLE t1, t2;
#
-# Test case for bug 7098: substitution of a constant for a string field
-#
-
-CREATE TABLE t1 ( city char(30) );
-INSERT INTO t1 VALUES ('London');
-INSERT INTO t1 VALUES ('Paris');
-
-SELECT * FROM t1 WHERE city='London';
-SELECT * FROM t1 WHERE city='london';
-EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london';
-SELECT * FROM t1 WHERE city='London' AND city='london';
-EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
-SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London';
-
-DROP TABLE t1;
-
-#
-# Bug#7425 inconsistent sort order on unsigned columns result of substraction
-#
-
-create table t1 (a int(11) unsigned, b int(11) unsigned);
-insert into t1 values (1,0), (1,1), (1,2);
-select a-b from t1 order by 1;
-select a-b , (a-b < 0) from t1 order by 1;
-select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
-select cast((a - b) as unsigned) from t1 order by 1;
-drop table t1;
-
-
-#
-# Bug#8733 server accepts malformed query (multiply mentioned distinct)
-#
-create table t1 (a int(11));
-select all all * from t1;
-select distinct distinct * from t1;
---error 1221
-select all distinct * from t1;
---error 1221
-select distinct all * from t1;
-drop table t1;
-
-#
-# Test for BUG#10095
-#
-CREATE TABLE t1 (
- kunde_intern_id int(10) unsigned NOT NULL default '0',
- kunde_id int(10) unsigned NOT NULL default '0',
- FK_firma_id int(10) unsigned NOT NULL default '0',
- aktuell enum('Ja','Nein') NOT NULL default 'Ja',
- vorname varchar(128) NOT NULL default '',
- nachname varchar(128) NOT NULL default '',
- geloescht enum('Ja','Nein') NOT NULL default 'Nein',
- firma varchar(128) NOT NULL default ''
-);
-
-INSERT INTO t1 VALUES
- (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
- (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
-
-
-SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
- WHERE
- (
- (
- ( '' != '' AND firma LIKE CONCAT('%', '', '%'))
- OR
- (vorname LIKE CONCAT('%', 'Vorname1', '%') AND
- nachname LIKE CONCAT('%', '1Nachname', '%') AND
- 'Vorname1' != '' AND 'xxxx' != '')
- )
- AND
- (
- aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
- )
- )
- ;
-
-SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
-geloescht FROM t1
- WHERE
- (
- (
- aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
- )
- AND
- (
- ( '' != '' AND firma LIKE CONCAT('%', '', '%') )
- OR
- ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
-nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
-'xxxx' != '')
- )
- )
- ;
-
-SELECT COUNT(*) FROM t1 WHERE
-( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
-AND FK_firma_id = 2;
-
-drop table t1;
-
-#
# Test for bug #10084: STRAIGHT_JOIN with ON expression
#
@@ -2276,3 +2290,54 @@ DROP TABLE t1,t2;
#
select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0;
+# Test for BUG#11700
+CREATE TABLE t1 (
+ acct_id int(11) NOT NULL default '0',
+ profile_id smallint(6) default NULL,
+ UNIQUE KEY t1$acct_id (acct_id),
+ KEY t1$profile_id (profile_id)
+);
+INSERT INTO t1 VALUES (132,17),(133,18);
+
+CREATE TABLE t2 (
+ profile_id smallint(6) default NULL,
+ queue_id int(11) default NULL,
+ seq int(11) default NULL,
+ KEY t2$queue_id (queue_id)
+);
+INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1);
+
+CREATE TABLE t3 (
+ id int(11) NOT NULL default '0',
+ qtype int(11) default NULL,
+ seq int(11) default NULL,
+ warn_lvl int(11) default NULL,
+ crit_lvl int(11) default NULL,
+ rr1 tinyint(4) NOT NULL default '0',
+ rr2 int(11) default NULL,
+ default_queue tinyint(4) NOT NULL default '0',
+ KEY t3$qtype (qtype),
+ KEY t3$id (id)
+);
+
+INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0),
+ (36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0);
+
+SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q
+WHERE
+ (pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND
+ (pq.queue_id = q.id) AND (q.rr1 <> 1);
+
+drop table t1,t2,t3;
+
+#
+# Bug #11482 4.1.12 produces different resultset for a complex query
+# than in previous 4.1.x
+create table t1 (f1 int);
+insert into t1 values (1),(NULL);
+create table t2 (f2 int, f3 int, f4 int);
+create index idx1 on t2 (f4);
+insert into t2 values (1,2,3),(2,4,6);
+select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3)
+from t2 C where A.f4 = C.f4) or A.f3 IS NULL;
+drop table t1,t2;
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index f74ffc4f4f5..d591f90dd65 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -376,3 +376,12 @@ show index from t1;
--disable_metadata
drop table t1;
+# Test for BUG#11635: mysqldump exports TYPE instead of USING for HASH
+create table t1 (
+ c1 int NOT NULL,
+ c2 int NOT NULL,
+ PRIMARY KEY USING HASH (c1),
+ INDEX USING BTREE(c2)
+);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index faf6d8b4de3..7f567449311 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -2,6 +2,10 @@
# Stored PROCEDURE error tests
#
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
# Make sure we don't have any procedures left.
delete from mysql.proc;
@@ -84,7 +88,7 @@ show create procedure foo|
--error 1305
show create function foo|
-# LEAVE/ITERATE/GOTO with no match
+# LEAVE/ITERATE with no match
--error 1308
create procedure foo()
foo: loop
@@ -100,47 +104,6 @@ create procedure foo()
foo: begin
iterate foo;
end|
---error 1308
-create procedure foo()
-begin
- goto foo;
-end|
---error 1308
-create procedure foo()
-begin
- begin
- label foo;
- end;
- goto foo;
-end|
---error 1308
-create procedure foo()
-begin
- goto foo;
- begin
- label foo;
- end;
-end|
---error 1308
-create procedure foo()
-begin
- begin
- goto foo;
- end;
- begin
- label foo;
- end;
-end|
---error 1308
-create procedure foo()
-begin
- begin
- label foo;
- end;
- begin
- goto foo;
- end;
-end|
# Redefining label
--error 1309
@@ -398,18 +361,6 @@ begin
declare c cursor for select * from t1;
end|
---error 1358
-create procedure p()
-begin
- declare continue handler for sqlexception
- begin
- goto L1;
- end;
-
- select field from t1;
- label L1;
-end|
-
# Check in and inout arguments.
--disable_warnings
drop procedure if exists p|
@@ -436,6 +387,29 @@ drop procedure p|
#
+# Let us test that we can access mysql.proc table for routines
+# definitions lookup without locking it explicitly.
+#
+create procedure p() begin end|
+lock table t1 read|
+# This should succeed
+call p()|
+unlock tables|
+drop procedure p|
+# Let us check restrictions which this ability puts on mysql.proc locking.
+--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
+lock tables t1 read, mysql.proc write|
+--error ER_WRONG_LOCK_OF_SYSTEM_TABLE
+lock tables mysql.proc write, mysql.user write|
+# Locking for read should be OK
+lock tables t1 read, mysql.proc read|
+unlock tables|
+# You also should be able lock only mysql.proc for write
+lock tables mysql.proc write|
+unlock tables|
+
+
+#
# BUG#1965
#
create procedure bug1965()
@@ -725,9 +699,7 @@ create procedure bug6600()
# BUG#9566: explicit LOCK TABLE and store procedures result in illegal state
#
# We should not think that mysql.proc table does not exist if we are unable
-# to open it under LOCK TABLE or in prelocked mode. Probably this test
-# should be removed when Monty will allow access to mysql.proc without
-# locking it.
+# to open it under LOCK TABLE or in prelocked mode.
#
--disable_warnings
drop procedure if exists bug9566|
@@ -737,9 +709,11 @@ begin
select * from t1;
end|
lock table t1 read|
-# This should fail because we forgot to lock mysql.proc table explicitly
+# This should fail since we forgot to lock mysql.proc for writing
+# explicitly, and we can't open mysql.proc for _writing_ if there
+# are locked tables.
--error 1100
-call bug9566()|
+alter procedure bug9566 comment 'Some comment'|
unlock tables|
# This should succeed
drop procedure bug9566|
@@ -923,9 +897,9 @@ end|
#
# BUG#9529: Stored Procedures: No Warning on truncation of procedure name
# during creation.
-#
+# Note: When using utf8 for mysql.proc, this limit is much higher than before
--error ER_TOO_LONG_IDENT
-create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890()
+create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123()
begin
end|
@@ -986,3 +960,115 @@ create procedure p() execute stmt;
create function f() returns int begin execute stmt;
deallocate prepare stmt;
+# BUG#9814: Closing a cursor that is not open
+create table t1(f1 int);
+create table t2(f1 int);
+
+delimiter |;
+CREATE PROCEDURE SP001()
+P1: BEGIN
+ DECLARE ENDTABLE INT DEFAULT 0;
+ DECLARE TEMP_NUM INT;
+ DECLARE TEMP_SUM INT;
+ DECLARE C1 CURSOR FOR SELECT F1 FROM t1;
+ DECLARE C2 CURSOR FOR SELECT F1 FROM t2;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET ENDTABLE = 1;
+
+ SET ENDTABLE=0;
+ SET TEMP_SUM=0;
+ SET TEMP_NUM=0;
+
+ OPEN C1;
+
+ FETCH C1 INTO TEMP_NUM;
+ WHILE ENDTABLE = 0 DO
+ SET TEMP_SUM=TEMP_NUM+TEMP_SUM;
+ FETCH C1 INTO TEMP_NUM;
+ END WHILE;
+ SELECT TEMP_SUM;
+ CLOSE C1;
+ CLOSE C1;
+ SELECT 'end of proc';
+END P1|
+delimiter ;|
+call SP001();
+drop procedure SP001;
+drop table t1, t2;
+
+# Bug #11394 "Recursion in SP crash server" and bug #11600 "Stored
+# procedures: crash with function calling itself".
+# We have to disable recursion since in many cases LEX and many
+# Item's can't be used in reentrant way nowdays.
+delimiter |;
+--disable_warnings
+drop function if exists bug11394|
+drop function if exists bug11394_1|
+drop function if exists bug11394_2|
+drop procedure if exists bug11394|
+--enable_warnings
+create function bug11394(i int) returns int
+begin
+ if i <= 0 then
+ return 0;
+ else
+ return (i in (100, 200, bug11394(i-1), 400));
+ end if;
+end|
+# If we allow recursive functions without additional modifications
+# this will crash server since Item for "IN" is not reenterable.
+--error 1424
+select bug11394(2)|
+drop function bug11394|
+create function bug11394_1(i int) returns int
+begin
+ if i <= 0 then
+ return 0;
+ else
+ return (select bug11394_1(i-1));
+ end if;
+end|
+# The following statement will crash because some LEX members responsible
+# for selects cannot be used in reentrant fashion.
+--error 1424
+select bug11394_1(2)|
+drop function bug11394_1|
+# Note that the following should be allowed since it does not contains
+# recursion
+create function bug11394_2(i int) returns int return i|
+select bug11394_2(bug11394_2(10))|
+drop function bug11394_2|
+create procedure bug11394(i int, j int)
+begin
+ if i > 0 then
+ call bug11394(i - 1,(select 1));
+ end if;
+end|
+# Again if we allow recursion for stored procedures (without
+# additional efforts) the following statement will crash the server.
+--error 1424
+call bug11394(2, 1)|
+drop procedure bug11394|
+delimiter ;|
+
+#
+# Bug#11834 "Re-execution of prepared statement with dropped function
+# crashes server". Also tests handling of prepared stmts which use
+# stored functions but does not require prelocking.
+#
+--disable_warnings
+drop function if exists bug11834_1;
+drop function if exists bug11834_2;
+--enable_warnings
+create function bug11834_1() returns int return 10;
+create function bug11834_2() returns int return bug11834_1();
+prepare stmt from "select bug11834_2()";
+execute stmt;
+# Re-execution of statement should not crash server.
+execute stmt;
+drop function bug11834_1;
+# Attempt to execute statement should return proper error and
+# should not crash server.
+--error ER_SP_DOES_NOT_EXIST
+execute stmt;
+deallocate prepare stmt;
+drop function bug11834_2;
diff --git a/mysql-test/t/sp-goto.test b/mysql-test/t/sp-goto.test
new file mode 100644
index 00000000000..e770dd285ff
--- /dev/null
+++ b/mysql-test/t/sp-goto.test
@@ -0,0 +1,238 @@
+#
+# The non-standard GOTO, for compatibility
+#
+# QQQ The "label" syntax is temporary, it will (hopefully)
+# change to the more common "L:" syntax soon.
+# For the time being, this feature is disabled, until
+# the syntax (and some other known bugs) can be fixed.
+#
+# Test cases for bugs are added at the end. See template there.
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (
+ id char(16) not null default '',
+ data int not null
+);
+
+delimiter //;
+
+--disable_warnings
+drop procedure if exists goto1//
+--enable_warnings
+create procedure goto1()
+begin
+ declare y int;
+
+label a;
+ select * from t1;
+ select count(*) into y from t1;
+ if y > 2 then
+ goto b;
+ end if;
+ insert into t1 values ("j", y);
+ goto a;
+label b;
+end//
+
+call goto1()//
+drop procedure goto1//
+
+# With dummy handlers, just to test restore of contexts with jumps
+--disable_warnings
+drop procedure if exists goto2//
+--enable_warnings
+create procedure goto2(a int)
+begin
+ declare x int default 0;
+ declare continue handler for sqlstate '42S98' set x = 1;
+
+label a;
+ select * from t1;
+b:
+ while x < 2 do
+ begin
+ declare continue handler for sqlstate '42S99' set x = 2;
+
+ if a = 0 then
+ set x = x + 1;
+ iterate b;
+ elseif a = 1 then
+ leave b;
+ elseif a = 2 then
+ set a = 1;
+ goto a;
+ end if;
+ end;
+ end while b;
+
+ select * from t1;
+end//
+
+call goto2(0)//
+call goto2(1)//
+call goto2(2)//
+
+drop procedure goto2//
+delete from t1//
+
+# Check label visibility for some more cases. We don't call these.
+--disable_warnings
+drop procedure if exists goto3//
+--enable_warnings
+create procedure goto3()
+begin
+ label L1;
+ begin
+ end;
+ goto L1;
+end//
+drop procedure goto3//
+
+--disable_warnings
+drop procedure if exists goto4//
+--enable_warnings
+create procedure goto4()
+begin
+ begin
+ label lab1;
+ begin
+ goto lab1;
+ end;
+ end;
+end//
+drop procedure goto4//
+
+--disable_warnings
+drop procedure if exists goto5//
+--enable_warnings
+create procedure goto5()
+begin
+ begin
+ begin
+ goto lab1;
+ end;
+ label lab1;
+ end;
+end//
+drop procedure goto5//
+
+--disable_warnings
+drop procedure if exists goto6//
+--enable_warnings
+create procedure goto6()
+begin
+ label L1;
+ goto L5;
+ begin
+ label L2;
+ goto L1;
+ goto L5;
+ begin
+ label L3;
+ goto L1;
+ goto L2;
+ goto L3;
+ goto L4;
+ goto L5;
+ end;
+ goto L2;
+ goto L4;
+ label L4;
+ end;
+ label L5;
+ goto L1;
+end//
+drop procedure goto6//
+
+# Mismatching labels
+--error 1308
+create procedure foo()
+begin
+ goto foo;
+end//
+--error 1308
+create procedure foo()
+begin
+ begin
+ label foo;
+ end;
+ goto foo;
+end//
+--error 1308
+create procedure foo()
+begin
+ goto foo;
+ begin
+ label foo;
+ end;
+end//
+--error 1308
+create procedure foo()
+begin
+ begin
+ goto foo;
+ end;
+ begin
+ label foo;
+ end;
+end//
+--error 1308
+create procedure foo()
+begin
+ begin
+ label foo;
+ end;
+ begin
+ goto foo;
+ end;
+end//
+
+# No goto in a handler
+--error 1358
+create procedure p()
+begin
+ declare continue handler for sqlexception
+ begin
+ goto L1;
+ end;
+
+ select field from t1;
+ label L1;
+end//
+
+
+#
+# Test cases for old bugs
+#
+
+#
+# BUG#6898: Stored procedure crash if GOTO statements exist
+#
+--disable_warnings
+drop procedure if exists bug6898//
+--enable_warnings
+create procedure bug6898()
+begin
+ goto label1;
+ label label1;
+ begin end;
+ goto label1;
+end//
+drop procedure bug6898//
+
+#
+# BUG#NNNN: New bug synopsis
+#
+#--disable_warnings
+#drop procedure if exists bugNNNN//
+#--enable_warnings
+#create procedure bugNNNN...
+
+
+# Add bugs above this line. Use existing tables t1 and t2 when
+# practical, or create table t3, t4 etc temporarily (and drop them).
+delimiter ;//
+drop table t1;
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index e1d8043ccda..15fcba5ebe9 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -15,6 +15,7 @@ grant usage on *.* to user1@localhost;
flush privileges;
--disable_warnings
+drop table if exists t1;
drop database if exists db1_secret;
--enable_warnings
# Create our secret database
@@ -304,3 +305,69 @@ drop database sptest;
delete from mysql.user where user='usera' or user='userb' or user='userc';
delete from mysql.procs_priv where user='usera' or user='userb' or user='userc';
+#
+# BUG#9503: reseting correct parameters of thread after error in SP function
+#
+connect (root,localhost,root,,test);
+connection root;
+
+--disable_warnings
+drop function if exists bug_9503;
+--enable_warnings
+delimiter //;
+create database mysqltest//
+use mysqltest//
+create table t1 (s1 int)//
+grant select on t1 to user1@localhost//
+create function bug_9503 () returns int sql security invoker begin declare v int;
+select min(s1) into v from t1; return v; end//
+delimiter ;//
+
+connect (user1,localhost,user1,,test);
+connection user1;
+use mysqltest;
+-- error 1370
+select bug_9503();
+
+connection root;
+grant execute on function bug_9503 to user1@localhost;
+
+connection user1;
+do 1;
+use test;
+
+connection root;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop function bug_9503;
+use test;
+drop database mysqltest;
+
+#
+# correct value from current_user() in function run from "security definer"
+# (BUG#7291)
+#
+connection con1root;
+use test;
+
+select current_user();
+select user();
+create procedure bug7291_0 () sql security invoker select current_user(), user();
+create procedure bug7291_1 () sql security definer call bug7291_0();
+create procedure bug7291_2 () sql security invoker call bug7291_0();
+grant execute on procedure bug7291_0 to user1@localhost;
+grant execute on procedure bug7291_1 to user1@localhost;
+grant execute on procedure bug7291_2 to user1@localhost;
+
+connect (user1,localhost,user1,,);
+connection user1;
+
+call bug7291_2();
+call bug7291_1();
+
+connection con1root;
+drop procedure bug7291_1;
+drop procedure bug7291_2;
+drop procedure bug7291_0;
+disconnect user1;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop user user1@localhost;
diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test
index 8fec5d14bc1..4c192f3e96f 100644
--- a/mysql-test/t/sp-threads.test
+++ b/mysql-test/t/sp-threads.test
@@ -112,6 +112,25 @@ drop procedure bug11158;
drop table t1, t2;
#
+# BUG#11554: Server crashes on statement indirectly using non-cached function
+#
+--disable_warnings
+drop function if exists bug11554;
+drop view if exists v1;
+--enable_warnings
+create table t1 (i int);
+create function bug11554 () returns int return 1;
+create view v1 as select bug11554() as f;
+connection con2root;
+# This should not crash server
+insert into t1 (select f from v1);
+# Clean-up
+connection con1root;
+drop function bug11554;
+drop table t1;
+drop view v1;
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 20b1a98702c..d9e6163cbc7 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -12,6 +12,7 @@
# Tests that check privilege and security issues go to sp-security.test.
# Tests that require multiple connections, except security/privilege tests,
# go to sp-thread.
+# Tests that uses 'goto' to into sp-goto.test (currently disabled)
use test;
@@ -585,139 +586,6 @@ delete from t1|
drop procedure i|
-# The non-standard GOTO, for compatibility
-#
-# QQQ The "label" syntax is temporary, it will (hopefully)
-# change to the more common "L:" syntax soon.
-#
---disable_warnings
-drop procedure if exists goto1|
---enable_warnings
-create procedure goto1()
-begin
- declare y int;
-
-label a;
- select * from t1;
- select count(*) into y from t1;
- if y > 2 then
- goto b;
- end if;
- insert into t1 values ("j", y);
- goto a;
-label b;
-end|
-
-call goto1()|
-drop procedure goto1|
-
-# With dummy handlers, just to test restore of contexts with jumps
---disable_warnings
-drop procedure if exists goto2|
---enable_warnings
-create procedure goto2(a int)
-begin
- declare x int default 0;
- declare continue handler for sqlstate '42S98' set x = 1;
-
-label a;
- select * from t1;
-b:
- while x < 2 do
- begin
- declare continue handler for sqlstate '42S99' set x = 2;
-
- if a = 0 then
- set x = x + 1;
- iterate b;
- elseif a = 1 then
- leave b;
- elseif a = 2 then
- set a = 1;
- goto a;
- end if;
- end;
- end while b;
-
- select * from t1;
-end|
-
-call goto2(0)|
-call goto2(1)|
-call goto2(2)|
-
-drop procedure goto2|
-delete from t1|
-
-# Check label visibility for some more cases. We don't call these.
---disable_warnings
-drop procedure if exists goto3|
---enable_warnings
-create procedure goto3()
-begin
- label L1;
- begin
- end;
- goto L1;
-end|
-drop procedure goto3|
-
---disable_warnings
-drop procedure if exists goto4|
---enable_warnings
-create procedure goto4()
-begin
- begin
- label lab1;
- begin
- goto lab1;
- end;
- end;
-end|
-drop procedure goto4|
-
---disable_warnings
-drop procedure if exists goto5|
---enable_warnings
-create procedure goto5()
-begin
- begin
- begin
- goto lab1;
- end;
- label lab1;
- end;
-end|
-drop procedure goto5|
-
---disable_warnings
-drop procedure if exists goto6|
---enable_warnings
-create procedure goto6()
-begin
- label L1;
- goto L5;
- begin
- label L2;
- goto L1;
- goto L5;
- begin
- label L3;
- goto L1;
- goto L2;
- goto L3;
- goto L4;
- goto L5;
- end;
- goto L2;
- goto L4;
- label L4;
- end;
- label L5;
- goto L1;
-end|
-drop procedure goto6|
-
# SELECT with one of more result set sent back to the clinet
insert into t1 values ("foo", 3), ("bar", 19)|
insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)|
@@ -1364,8 +1232,9 @@ begin
end|
select f5(1)|
# This should generate an error about insuficient number of tables locked
---error 1100
-select f5(2)|
+# Nuw this crash server, comented until bug#11394 fix
+#--error 1100
+#select f5(2)|
# But now it simply miserably fails because we are trying to use the same
# lex on the next iteration :/ It should generate some error too...
# select f5(3)|
@@ -1414,7 +1283,8 @@ select * from v1|
# views and functions ?
create function f1() returns int
return (select sum(data) from t1) + (select sum(data) from v1)|
-# FIXME All these just exceed file limit for me :)
+# This queries will crash server because we can't use LEX in
+# reenterable fashion yet. Patch disabling recursion will heal this.
#select f1()|
#select * from v1|
#select * from v2|
@@ -1459,15 +1329,12 @@ select * from v2|
select * from v1|
# These should not work as we have too little instances of tables locked
--error 1100
-select * from v1, v2|
+select * from v1, t1|
--error 1100
select f4()|
unlock tables|
-# TODO We also should test integration with triggers
-
-
# Cleanup
drop function f0|
drop function f1|
@@ -1629,54 +1496,56 @@ show procedure status like '%p%'|
# Fibonacci, for recursion test. (Yet Another Numerical series :)
-
---disable_warnings
-drop table if exists fib|
---enable_warnings
-create table fib ( f bigint unsigned not null )|
-
-# We deliberately do it the awkward way, fetching the last two
-# values from the table, in order to exercise various statements
-# and table accesses at each turn.
---disable_warnings
-drop procedure if exists fib|
---enable_warnings
-create procedure fib(n int unsigned)
-begin
- if n > 1 then
- begin
- declare x, y bigint unsigned;
- declare c cursor for select f from fib order by f desc limit 2;
-
- open c;
- fetch c into y;
- fetch c into x;
- close c;
- insert into fib values (x+y);
- call fib(n-1);
- end;
- end if;
-end|
-
-# Minimum test: recursion of 3 levels
-
-insert into fib values (0), (1)|
-
-call fib(3)|
-
-select * from fib order by f asc|
-
-delete from fib|
-
-# Original test: 20 levels (may run into memory limits!)
-
-insert into fib values (0), (1)|
-
-call fib(20)|
-
-select * from fib order by f asc|
-drop table fib|
-drop procedure fib|
+#
+# This part of test is disabled until we implement support for
+# recursive stored procedures.
+#--disable_warnings
+#drop table if exists fib|
+#--enable_warnings
+#create table fib ( f bigint unsigned not null )|
+#
+## We deliberately do it the awkward way, fetching the last two
+## values from the table, in order to exercise various statements
+## and table accesses at each turn.
+#--disable_warnings
+#drop procedure if exists fib|
+#--enable_warnings
+#create procedure fib(n int unsigned)
+#begin
+# if n > 1 then
+# begin
+# declare x, y bigint unsigned;
+# declare c cursor for select f from fib order by f desc limit 2;
+#
+# open c;
+# fetch c into y;
+# fetch c into x;
+# close c;
+# insert into fib values (x+y);
+# call fib(n-1);
+# end;
+# end if;
+#end|
+#
+## Minimum test: recursion of 3 levels
+#
+#insert into fib values (0), (1)|
+#
+#call fib(3)|
+#
+#select * from fib order by f asc|
+#
+#delete from fib|
+#
+## Original test: 20 levels (may run into memory limits!)
+#
+#insert into fib values (0), (1)|
+#
+#call fib(20)|
+#
+#select * from fib order by f asc|
+#drop table fib|
+#drop procedure fib|
#
@@ -3010,24 +2879,26 @@ drop table t3|
#
# BUG#6022: Stored procedure shutdown problem with self-calling function.
#
---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|
+# 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|
#
# BUG#6029: Stored procedure specific handlers should have priority
@@ -3506,15 +3377,16 @@ drop procedure avg|
--disable_warnings
drop procedure if exists bug6129|
--enable_warnings
-set @@sql_mode = 'traditional'|
-create procedure bug6129(mode text)
- select @@sql_mode = mode|
-
-# 1
-call bug6129(@@sql_mode)|
-set @@sql_mode = ''|
-# 0
-call bug6129(@@sql_mode)|
+set @old_mode= @@sql_mode;
+set @@sql_mode= "";
+create procedure bug6129()
+ select @@sql_mode|
+call bug6129()|
+set @@sql_mode= "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO"|
+call bug6129()|
+set @@sql_mode= "NO_ZERO_IN_DATE"|
+call bug6129()|
+set @@sql_mode=@old_mode;
drop procedure bug6129|
@@ -3634,22 +3506,6 @@ drop function bug9902|
#
-# BUG#6898: Stored procedure crash if GOTO statements exist
-#
---disable_warnings
-drop procedure if exists bug6898|
---enable_warnings
-create procedure bug6898()
-begin
- goto label1;
- label label1;
- begin end;
- goto label1;
-end|
-drop procedure bug6898|
-
-
-#
# BUG#9102: Stored proccedures: function which returns blob causes crash
#
--disable_warnings
@@ -3887,6 +3743,140 @@ DROP VIEW tv|
DROP TABLE tt1, tt2, tt3|
#
+# BUG#10136: items cleunup
+#
+--disable_warnings
+DROP PROCEDURE IF EXISTS bug10136|
+--enable_warnings
+create table t3 ( name char(5) not null primary key, val float not null)|
+insert into t3 values ('aaaaa', 1), ('bbbbb', 2), ('ccccc', 3)|
+create procedure bug10136()
+begin
+ declare done int default 3;
+
+ repeat
+ select * from t3;
+ set done = done - 1;
+ until done <= 0 end repeat;
+
+end|
+call bug10136()|
+call bug10136()|
+call bug10136()|
+drop procedure bug10136|
+drop table t3|
+
+#
+# BUG#11529: crash server after use stored procedure
+#
+--disable_warnings
+drop procedure if exists bug11529|
+--enable_warnings
+create procedure bug11529()
+begin
+ declare c cursor for select id, data from t1 where data in (10,13);
+
+ open c;
+ begin
+ declare vid char(16);
+ declare vdata int;
+ declare exit handler for not found begin end;
+
+ while true do
+ fetch c into vid, vdata;
+ end while;
+ end;
+ close c;
+end|
+
+insert into t1 values
+ ('Name1', 10),
+ ('Name2', 11),
+ ('Name3', 12),
+ ('Name4', 13),
+ ('Name5', 14)|
+
+call bug11529()|
+call bug11529()|
+delete from t1|
+drop procedure bug11529|
+
+
+#
+# BUG#6063: Stored procedure labels are subject to restrictions (partial)
+# BUG#7088: Stored procedures: labels won't work if character set is utf8
+#
+--disable_warnings
+drop procedure if exists bug6063|
+drop procedure if exists bug7088_1|
+drop procedure if exists bug7088_2|
+--enable_warnings
+
+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|
+
+#
+# BUG#9565: "Wrong locking in stored procedure if a sub-sequent procedure
+# is called".
+#
+--disable_warnings
+drop procedure if exists bug9565_sub|
+drop procedure if exists bug9565|
+--enable_warnings
+create procedure bug9565_sub()
+begin
+ select * from t1;
+end|
+create procedure bug9565()
+begin
+ insert into t1 values ("one", 1);
+ call bug9565_sub();
+end|
+call bug9565()|
+delete from t1|
+drop procedure bug9565_sub|
+drop procedure bug9565|
+
+
+#
+# BUG#9538: SProc: Creation fails if we try to SET system variable
+# using @@var_name in proc
+#
+--disable_warnings
+drop procedure if exists bug9538|
+--enable_warnings
+create procedure bug9538()
+ set @@sort_buffer_size = 1000000|
+
+set @x = @@sort_buffer_size|
+set @@sort_buffer_size = 2000000|
+select @@sort_buffer_size|
+call bug9538()|
+select @@sort_buffer_size|
+set @@sort_buffer_size = @x|
+
+drop procedure bug9538|
+
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
@@ -3896,7 +3886,6 @@ DROP TABLE tt1, tt2, tt3|
# Add bugs above this line. Use existing tables t1 and t2 when
-# practical, or create table t3, t3 etc temporarily (and drop them).
+# practical, or create table t3, t4 etc temporarily (and drop them).
delimiter ;|
drop table t1,t2;
-
diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test
index 6a0c4aecada..f8ab521e665 100644
--- a/mysql-test/t/sql_mode.test
+++ b/mysql-test/t/sql_mode.test
@@ -189,4 +189,55 @@ SET @@SQL_MODE='';
SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b';
SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b";
+#
+# Bug#6877: MySQL should give an error if the requested table type
+# is not available
+#
+
+set session sql_mode = 'NO_ENGINE_SUBSTITUTION';
+--error 1289
+create table t1 (a int) engine=isam;
+--error 1146
+show create table t1;
+drop table if exists t1;
+
+# for comparison, lets see the warnings...
+set session sql_mode = '';
+create table t1 (a int) engine=isam;
+show create table t1;
+drop table t1;
+
+#
+# Bug #6903: ANSI_QUOTES does not come into play with SHOW CREATE FUNCTION
+# or PROCEDURE because it displays the SQL_MODE used to create the routine.
+#
+SET @@SQL_MODE='';
+create function `foo` () returns int return 5;
+show create function `foo`;
+SET @@SQL_MODE='ANSI_QUOTES';
+show create function `foo`;
+drop function `foo`;
+
+create function `foo` () returns int return 5;
+show create function `foo`;
+SET @@SQL_MODE='';
+show create function `foo`;
+drop function `foo`;
+
+#
+# Bug #6903: ANSI_QUOTES should have effect for SHOW CREATE VIEW (Bug #6903)
+#
+SET @@SQL_MODE='';
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select a from t1;
+show create view v1;
+SET @@SQL_MODE='ANSI_QUOTES';
+show create view v1;
+# Test a view with a subselect, which will get shown incorrectly without
+# thd->lex->view_prepare_mode set properly.
+create view v2 as select a from t2 where a in (select a from v1);
+drop view v2, v1;
+drop table t1, t2;
+
SET @@SQL_MODE=@OLD_SQL_MODE;
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
index 302acc9bef2..6ac88e4d629 100644
--- a/mysql-test/t/strict.test
+++ b/mysql-test/t/strict.test
@@ -1093,3 +1093,13 @@ set @@sql_mode='traditional';
create table t1(a varchar(65537));
--error 1074
create table t1(a varbinary(65537));
+
+#
+# Bug #9881: problem with altering table
+#
+
+set @@sql_mode='traditional';
+create table t1(a int, b date not null);
+alter table t1 modify a bigint unsigned not null;
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 2e6cea8468b..ecb3432753d 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1837,3 +1837,33 @@ WHERE t1.EMPNUM NOT IN
WHERE t1.EMPNUM = t2.EMPNUM);
select * from t1;
DROP TABLE t1,t2;
+
+#
+# Test for bug #11487: range access in a subquery
+#
+
+CREATE TABLE t1(select_id BIGINT, values_id BIGINT);
+INSERT INTO t1 VALUES (1, 1);
+CREATE TABLE t2 (select_id BIGINT, values_id BIGINT,
+ PRIMARY KEY(select_id,values_id));
+INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5);
+
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+ WHERE select_id IN (1, 0));
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+ WHERE select_id BETWEEN 0 AND 1);
+SELECT values_id FROM t1
+WHERE values_id IN (SELECT values_id FROM t2
+ WHERE select_id = 0 OR select_id = 1);
+
+DROP TABLE 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;
+
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 0c5ef077159..8a27636ed84 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -3,9 +3,10 @@
#
--disable_warnings
-drop table if exists t1, t2;
+drop table if exists t1, t2, t3;
drop view if exists v1;
drop database if exists mysqltest;
+drop function if exists f1;
--enable_warnings
create table t1 (i int);
@@ -200,6 +201,84 @@ drop table t1;
#
+# Let us test triggers which access other tables.
+#
+# Trivial trigger which inserts data into another table
+create table t1 (id int primary key, data varchar(10), fk int);
+create table t2 (event varchar(100));
+create table t3 (id int primary key);
+create trigger t1_ai after insert on t1 for each row
+ insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "'"));
+insert into t1 (id, data) values (1, "one"), (2, "two");
+select * from t1;
+select * from t2;
+drop trigger t1.t1_ai;
+# Trigger which uses couple of tables (and partially emulates FK constraint)
+delimiter |;
+create trigger t1_bi before insert on t1 for each row
+begin
+ if exists (select id from t3 where id=new.fk) then
+ insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "' fk=", new.fk));
+ else
+ insert into t2 values (concat("INSERT INTO t1 FAILED id=", new.id, " data='", new.data, "' fk=", new.fk));
+ set new.id= NULL;
+ end if;
+end|
+delimiter ;|
+insert into t3 values (1);
+--error 1048
+insert into t1 values (4, "four", 1), (5, "five", 2);
+select * from t1;
+select * from t2;
+drop table t1, t2, t3;
+# Trigger which invokes function
+create table t1 (id int primary key, data varchar(10));
+create table t2 (seq int);
+insert into t2 values (10);
+create function f1 () returns int return (select max(seq) from t2);
+delimiter |;
+create trigger t1_bi before insert on t1 for each row
+begin
+ if new.id > f1() then
+ set new.id:= f1();
+ end if;
+end|
+delimiter ;|
+insert into t1 values (1, "first");
+insert into t1 values (f1(), "max");
+select * from t1;
+drop table t1, t2;
+drop function f1;
+# Trigger which forces invocation of another trigger
+# (emulation of FK on delete cascade policy)
+create table t1 (id int primary key, fk_t2 int);
+create table t2 (id int primary key, fk_t3 int);
+create table t3 (id int primary key);
+insert into t1 values (1,1), (2,1), (3,2);
+insert into t2 values (1,1), (2,2);
+insert into t3 values (1), (2);
+create trigger t3_ad after delete on t3 for each row
+ delete from t2 where fk_t3=old.id;
+create trigger t2_ad after delete on t2 for each row
+ delete from t1 where fk_t2=old.id;
+delete from t3 where id = 1;
+select * from t1 left join (t2 left join t3 on t2.fk_t3 = t3.id) on t1.fk_t2 = t2.id;
+drop table t1, t2, t3;
+# Trigger which assigns value selected from table to field of row
+# being inserted/updated.
+create table t1 (id int primary key, copy int);
+create table t2 (id int primary key, data int);
+insert into t2 values (1,1), (2,2);
+create trigger t1_bi before insert on t1 for each row
+ set new.copy= (select data from t2 where id = new.id);
+create trigger t1_bu before update on t1 for each row
+ set new.copy= (select data from t2 where id = new.id);
+insert into t1 values (1,3), (2,4), (3,3);
+update t1 set copy= 1 where id = 2;
+select * from t1;
+drop table t1, t2;
+
+#
# Test of wrong column specifiers in triggers
#
create table t1 (i int);
@@ -238,7 +317,7 @@ drop trigger t1.trg;
drop trigger t1.trg;
create view v1 as select * from t1;
---error 1361
+--error 1347
create trigger trg before insert on v1 for each row set @a:=1;
drop view v1;
@@ -494,3 +573,21 @@ replace into t1 (i, k) values (2, 11);
select * from t1;
# Also drops all triggers
drop table t1, t2;
+
+# Test for bug #5893 "Triggers with dropped functions cause crashes"
+# Appropriate error should be reported instead of crash.
+# Also test for bug #11889 "Server crashes when dropping trigger
+# using stored routine".
+--disable_warnings
+drop function if exists bug5893;
+--enable_warnings
+create table t1 (col1 int, col2 int);
+insert into t1 values (1, 2);
+create function bug5893 () returns int return 5;
+create trigger t1_bu before update on t1 for each row set new.col1= bug5893();
+drop function bug5893;
+--error 1305
+update t1 set col2 = 4;
+# This should not crash server too.
+drop trigger t1.t1_bu;
+drop table t1;
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
index 2df5f0ed05d..fd5eb49858c 100644
--- a/mysql-test/t/type_bit.test
+++ b/mysql-test/t/type_bit.test
@@ -171,3 +171,56 @@ create table t1 (a bit(8)) engine=heap;
insert into t1 values ('1111100000');
select a+0 from t1;
drop table t1;
+
+#
+# Bug #11091: union
+#
+
+create table t1 (a bit(7));
+insert into t1 values (120), (0), (111);
+select a+0 from t1 union select a+0 from t1;
+select a+0 from t1 union select NULL;
+select NULL union select a+0 from t1;
+create table t2 select a from t1 union select a from t1;
+select a+0 from t2;
+show create table t2;
+drop table t1, t2;
+
+#
+# Bug #11572: view
+#
+
+create table t1 (id1 int(11), b1 bit(1));
+create table t2 (id2 int(11), b2 bit(1));
+insert into t1 values (1, 1), (2, 0), (3, 1);
+insert into t2 values (2, 1), (3, 0), (4, 0);
+create algorithm=undefined view v1 as
+ select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0
+ union
+ select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1;
+select * from v1;
+drop table t1, t2;
+drop view v1;
+
+#
+# Bug #10617: bulk-insert
+#
+
+create table t1(a bit(4));
+insert into t1(a) values (1), (2), (5), (4), (3);
+insert into t1 select * from t1;
+select a+0 from t1;
+drop table t1;
+
+#
+# join
+#
+
+create table t1 (a1 int(11), b1 bit(2));
+create table t2 (a2 int(11), b2 bit(2));
+insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2);
+insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2);
+select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2;
+select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1;
+select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2;
+select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1;
diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test
index c33ea3f435d..80aabf6c5e0 100644
--- a/mysql-test/t/type_blob.test
+++ b/mysql-test/t/type_blob.test
@@ -394,4 +394,11 @@ INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,'');
select max(i) from t1 where c = '';
drop table t1;
-
+#
+# Bug#11657: Creation of secondary index fails
+#
+create table t1 (a int, b int, c tinyblob, d int, e int);
+alter table t1 add primary key (a,b,c(255),d);
+alter table t1 add key (a,b,d,e);
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test
index 7ce54847506..2901592fd9e 100644
--- a/mysql-test/t/type_decimal.test
+++ b/mysql-test/t/type_decimal.test
@@ -247,9 +247,8 @@ CREATE TABLE t1 (a_dec DECIMAL(-1,0));
CREATE TABLE t1 (a_dec DECIMAL(-2,1));
--error 1064
CREATE TABLE t1 (a_dec DECIMAL(-1,1));
+--error 1427
CREATE TABLE t1 (a_dec DECIMAL(0,11));
-SHOW CREATE TABLE t1;
-DROP TABLE t1;
#
# Zero prepend overflow bug
@@ -293,21 +292,13 @@ create table t1 (d decimal(64,0));
insert into t1 values (1);
select * from t1;
drop table t1;
-create table t1 (d decimal(64,99));
-show create table t1;
-insert into t1 values (1);
-select * from t1;
-drop table t1;
-create table t1 (d decimal(10,12));
-show create table t1;
-drop table t1;
create table t1 (d decimal(5));
show create table t1;
drop table t1;
create table t1 (d decimal);
show create table t1;
drop table t1;
---error 1063
+--error 1426
create table t1 (d decimal(66,0));
#
diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test
index 41812ef2652..a27fd4c58b4 100644
--- a/mysql-test/t/type_float.test
+++ b/mysql-test/t/type_float.test
@@ -67,7 +67,7 @@ drop table t1;
# FLOAT/DOUBLE/DECIMAL handling
#
-create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6));
+create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6));
# We mask out Privileges column because it differs for embedded server
--replace_column 8 #
show full columns from t1;
@@ -79,11 +79,8 @@ select a from t1 order by a;
select min(a) from t1;
drop table t1;
+--error 1425
create table t1 (a float(200,100), b double(200,100));
-insert t1 values (1.0, 2.0);
-select * from t1;
-show create table t1;
-drop table t1;
#
# float in a char(1) field
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index 6199bd34fa9..f295311fe4e 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -908,18 +908,6 @@ SELECT * FROM t1;
DROP TABLE t1;
#
-# Bug #10465
-#
-
---disable_warnings
-CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB;
---enable_warnings
-INSERT INTO t1 (GRADE) VALUES (151),(252),(343);
-SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300;
-SELECT GRADE FROM t1 WHERE GRADE= 151;
-DROP TABLE t1;
-
-#
# Bug #10599: problem with NULL
#
@@ -964,3 +952,54 @@ insert into t1 values (0.00);
select * from t1 where a > -0.00;
select * from t1 where a = -0.00;
drop table t1;
+
+#
+# Bug #11215: a problem with LONGLONG_MIN
+#
+
+create table t1 (col1 bigint default -9223372036854775808);
+insert into t1 values (default);
+select * from t1;
+drop table t1;
+
+#
+# Bug #10891 (converting to decimal crashes server)
+#
+select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15));
+
+#
+# Bug #11708 (conversion to decimal fails in decimal part)
+#
+select ln(14000) c1, convert(ln(14000),decimal(2,3)) c2, cast(ln(14000) as decimal(2,3)) c3;
+
+#
+# Bug #8449 (Silent column changes)
+#
+--error 1426
+create table t1 (sl decimal(70,30));
+--error 1425
+create table t1 (sl decimal(32,31));
+--error 1425
+create table t1 (sl decimal(0,38));
+--error 1427
+create table t1 (sl decimal(0,30));
+create table t1 (sl decimal(5, 5));
+show create table t1;
+drop table t1;
+
+#
+# Bug 11557 (DEFAULT values rounded improperly
+#
+create table t1 (
+ f1 decimal unsigned not null default 17.49,
+ f2 decimal unsigned not null default 17.68,
+ f3 decimal unsigned not null default 99.2,
+ f4 decimal unsigned not null default 99.7,
+ f5 decimal unsigned not null default 104.49,
+ f6 decimal unsigned not null default 199.91,
+ f7 decimal unsigned not null default 999.9,
+ f8 decimal unsigned not null default 9999.99);
+insert into t1 (f1) values (1);
+select * from t1;
+drop table t1;
+
diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test
index 6a90fb95760..21789a550b9 100644
--- a/mysql-test/t/update.test
+++ b/mysql-test/t/update.test
@@ -31,7 +31,7 @@ CREATE TABLE t1
clicks int(10) unsigned DEFAULT '0' NOT NULL,
iclicks int(10) unsigned DEFAULT '0' NOT NULL,
uclicks int(10) unsigned DEFAULT '0' NOT NULL,
- ts timestamp(14),
+ ts timestamp,
PRIMARY KEY (place_id,ts)
);
@@ -52,7 +52,7 @@ CREATE TABLE t1 (
replyto varchar(255) NOT NULL default '',
subject varchar(100) NOT NULL default '',
timestamp int(10) unsigned NOT NULL default '0',
- tstamp timestamp(14) NOT NULL,
+ tstamp timestamp NOT NULL,
status int(3) NOT NULL default '0',
type varchar(15) NOT NULL default '',
assignment int(10) unsigned NOT NULL default '0',
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index f8d833b6b73..c3ffdc79c16 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -373,9 +373,13 @@ drop table t1;
#
# Bug #6993: myisam_data_pointer_size
+# Wrong bug report, data pointer size must be restricted to 7,
+# setting to 8 will not work on all computers, myisamchk and
+# the server may see a wrong value, such as 0 or negative number
+# if 8 bytes is set.
#
-SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8;
+SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7;
SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE';
#
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 0477ab0ea20..a98ecfe232f 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -83,8 +83,7 @@ explain extended select c from v6;
# show table/table status test
show tables;
show full tables;
---replace_column 12 # 13 #
---replace_result 2147483647 38654705663
+--replace_column 8 # 12 # 13 #
show table status;
drop view v1,v2,v3,v4,v5,v6;
@@ -1569,3 +1568,288 @@ drop procedure p1;
drop view v1;
drop table t1;
+#
+# Bug#7422 "order by" doesn't work
+#
+CREATE TABLE t1(a char(2) primary key, b char(2));
+CREATE TABLE t2(a char(2), b char(2), index i(a));
+INSERT INTO t1 VALUES ('a','1'), ('b','2');
+INSERT INTO t2 VALUES ('a','5'), ('a','6'), ('b','5'), ('b','6');
+CREATE VIEW v1 AS
+ SELECT t1.b as c, t2.b as d FROM t1,t2 WHERE t1.a=t2.a;
+SELECT d, c FROM v1 ORDER BY d,c;
+DROP VIEW v1;
+DROP TABLE t1, t2;
+#
+# using sum(distinct ) & avg(distinct ) in views (BUG#7015)
+#
+create table t1 (s1 int);
+create view v1 as select sum(distinct s1) from t1;
+select * from v1;
+drop view v1;
+create view v1 as select avg(distinct s1) from t1;
+select * from v1;
+drop view v1;
+drop table t1;
+
+#
+# using cast(... as decimal) in views (BUG#11387);
+#
+create view v1 as select cast(1 as decimal);
+select * from v1;
+drop view v1;
+
+#
+# Bug#11298 insert into select from VIEW produces incorrect result when
+# using ORDER BY
+create table t1(f1 int);
+create table t2(f2 int);
+insert into t1 values(1),(2),(3);
+insert into t2 values(1),(2),(3);
+create view v1 as select * from t1,t2 where f1=f2;
+create table t3 (f1 int, f2 int);
+insert into t3 select * from v1 order by 1;
+select * from t3;
+drop view v1;
+drop table t1,t2,t3;
+
+#
+# Generation unique names for columns, and correct names check (BUG#7448)
+#
+# names with ' and \
+create view v1 as select '\\','\\shazam';
+select * from v1;
+drop view v1;
+create view v1 as select '\'','\shazam';
+select * from v1;
+drop view v1;
+# autogenerated names differ by case only
+create view v1 as select 'k','K';
+select * from v1;
+drop view v1;
+create table t1 (s1 int);
+# same autogenerated names
+create view v1 as select s1, 's1' from t1;
+select * from v1;
+drop view v1;
+create view v1 as select 's1', s1 from t1;
+select * from v1;
+drop view v1;
+# set name as one of expected autogenerated
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+select * from v1;
+drop view v1;
+create view v1 as select 1 as My_exp_s1, 's1', s1 from t1;
+select * from v1;
+drop view v1;
+# set name conflict with autogenerated names
+create view v1 as select 1 as s1, 's1', 's1' from t1;
+select * from v1;
+drop view v1;
+create view v1 as select 's1', 's1', 1 as s1 from t1;
+select * from v1;
+drop view v1;
+# underlying field name conflict with autogenerated names
+create view v1 as select s1, 's1', 's1' from t1;
+select * from v1;
+drop view v1;
+create view v1 as select 's1', 's1', s1 from t1;
+select * from v1;
+drop view v1;
+# underlying field name conflict with set name
+-- error 1060
+create view v1 as select 1 as s1, 's1', s1 from t1;
+-- error 1060
+create view v1 as select 's1', s1, 1 as s1 from t1;
+drop table t1;
+# set names differ by case only
+-- error 1060
+create view v1(k, K) as select 1,2;
+
+#
+# using time_format in view (BUG#7521)
+#
+create view v1 as SELECT TIME_FORMAT(SEC_TO_TIME(3600),'%H:%i') as t;
+select * from v1;
+drop view v1;
+
+#
+# evaluation constant functions in WHERE (BUG#4663)
+#
+create table t1 (a timestamp default now());
+create table t2 (b timestamp default now());
+create view v1 as select a,b,t1.a < now() from t1,t2 where t1.a < now();
+SHOW CREATE VIEW v1;
+drop view v1;
+drop table t1, t2;
+CREATE TABLE t1 ( a varchar(50) );
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = CURRENT_USER();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = VERSION();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = DATABASE();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# checking views after some view with error (BUG#11337)
+#
+CREATE TABLE t1 (col1 time);
+CREATE TABLE t2 (col1 time);
+CREATE VIEW v1 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v2 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+CREATE VIEW v3 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v4 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+CREATE VIEW v5 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
+CREATE VIEW v6 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
+DROP TABLE t1;
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+drop view v1, v2, v3, v4, v5, v6;
+drop table t2;
+
+CREATE TABLE t1 (col1 time);
+CREATE TABLE t2 (col1 time);
+CREATE TABLE t3 (col1 time);
+create function f1 () returns int return (select max(col1) from t1);
+create function f2 () returns int return (select max(col1) from t2);
+CREATE VIEW v1 AS SELECT f1() FROM t3;
+CREATE VIEW v2 AS SELECT f2() FROM t3;
+CREATE VIEW v3 AS SELECT f1() FROM t3;
+CREATE VIEW v4 AS SELECT f2() FROM t3;
+CREATE VIEW v5 AS SELECT f1() FROM t3;
+CREATE VIEW v6 AS SELECT f2() FROM t3;
+drop function f1;
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+create function f1 () returns int return (select max(col1) from t1);
+DROP TABLE t1;
+# following will show underlying table until BUG#11555 fix
+CHECK TABLE v1, v2, v3, v4, v5, v6;
+drop function f1;
+drop function f2;
+drop view v1, v2, v3, v4, v5, v6;
+drop table t2,t3;
+
+#
+# bug #11325 Wrong date comparison in views
+#
+create table t1 (f1 date);
+insert into t1 values ('2005-01-01'),('2005-02-02');
+create view v1 as select * from t1;
+select * from v1 where f1='2005.02.02';
+select * from v1 where '2005.02.02'=f1;
+drop view v1;
+drop table t1;
+
+#
+# using encrypt & substring_index in view (BUG#7024)
+#
+CREATE VIEW v1 AS SELECT ENCRYPT("dhgdhgd");
+disable_result_log;
+SELECT * FROM v1;
+enable_result_log;
+drop view v1;
+CREATE VIEW v1 AS SELECT SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1);
+SELECT * FROM v1;
+drop view v1;
+
+#
+# Using var_samp with view (BUG#10651)
+#
+create table t1 (s1 int);
+create view v1 as select var_samp(s1) from t1;
+show create view v1;
+drop view v1;
+drop table t1;
+
+#
+# Correct inserting data check (absence of default value) for view
+# underlying tables (BUG#6443)
+#
+set sql_mode='strict_all_tables';
+CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB;
+CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1;
+CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2;
+-- error 1364
+INSERT INTO t1 (col1) VALUES(12);
+-- error 1423
+INSERT INTO v1 (vcol1) VALUES(12);
+-- error 1423
+INSERT INTO v2 (vcol1) VALUES(12);
+set sql_mode=default;
+drop view v2,v1;
+drop table t1;
+
+#
+# Bug#11399 Use an alias in a select statement on a view
+#
+create table t1 (f1 int);
+insert into t1 values (1);
+create view v1 as select f1 from t1;
+select f1 as alias from v1;
+drop view v1;
+drop table t1;
+
+#
+# Test for bug #6120: SP cache to be invalidated when altering a view
+#
+
+CREATE TABLE t1 (s1 int, s2 int);
+INSERT INTO t1 VALUES (1,2);
+CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1;
+SELECT * FROM v1;
+CREATE PROCEDURE p1 () SELECT * FROM v1;
+CALL p1();
+ALTER VIEW v1 AS SELECT s1 AS s1, s2 AS s2 FROM t1;
+CALL p1();
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1;
+CALL p1();
+
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# Test for bug #11709 View was ordered by wrong column
+#
+create table t1 (f1 int, f2 int);
+create view v1 as select f1 as f3, f2 as f1 from t1;
+insert into t1 values (1,3),(2,1),(3,2);
+select * from v1 order by f1;
+drop view v1;
+drop table t1;
+
+#
+# Test for bug #11771: wrong query_id in SELECT * FROM <view>
+#
+CREATE TABLE t1 (f1 char) ENGINE = innodb;
+INSERT INTO t1 VALUES ('A');
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+INSERT INTO t1 VALUES('B');
+SELECT * FROM v1;
+SELECT * FROM t1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
+# opening table in correct locking mode (BUG#9597)
+#
+CREATE TABLE t1 ( bug_table_seq INTEGER NOT NULL);
+CREATE OR REPLACE VIEW v1 AS SELECT * from t1;
+DROP PROCEDURE IF EXISTS p1;
+delimiter //;
+CREATE PROCEDURE p1 ( )
+BEGIN
+ DO (SELECT @next := IFNULL(max(bug_table_seq),0) + 1 FROM v1);
+ INSERT INTO t1 VALUES (1);
+END //
+delimiter ;//
+CALL p1();
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index bb603b75daa..6283a1abf11 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -360,7 +360,7 @@ create table mysqltest.v3 (b int);
grant select(b) on mysqltest.v3 to mysqltest_1@localhost;
drop table mysqltest.v3;
connection user1;
--- error 1142
+-- error 1143
create view mysqltest.v3 as select b from mysqltest.t2;
# Expression need select privileges
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 03ee692645f..4a35b9f9c39 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -17,7 +17,8 @@
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
-INCLUDES = @ZLIB_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir)
+INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
+ -I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a ../dbug/libdbug.a \
../strings/libmystrings.a
diff --git a/mysys/charset.c b/mysys/charset.c
index cbd9ba16b4c..4920e7806a2 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -561,11 +561,30 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
DBUG_RETURN(cs);
}
+
/*
+ Escape string with backslashes (\)
+
+ SYNOPSIS
+ escape_string_for_mysql()
+ charset_info Charset of the strings
+ to Buffer for escaped string
+ to_length Length of destination buffer, or 0
+ from The string to escape
+ length The length of the string to escape
+
+ DESCRIPTION
+ This escapes the contents of a string by adding backslashes before special
+ characters, and turning others into specific escape sequences, such as
+ turning newlines into \n and null bytes into \0.
+
NOTE
- to keep old C API, to_length may be 0 to mean "big enough"
- RETURN
- the length of the escaped string or ~0 if it did not fit.
+ To maintain compatibility with the old C API, to_length may be 0 to mean
+ "big enough"
+
+ RETURN VALUES
+ ~0 The escaped string did not fit in the to buffer
+ >=0 The length of the escaped string
*/
ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
char *to, ulong to_length,
@@ -573,20 +592,20 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
{
const char *to_start= to;
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
- my_bool overflow=0;
+ my_bool overflow= FALSE;
#ifdef USE_MB
my_bool use_mb_flag= use_mb(charset_info);
#endif
for (end= from + length; from < end; from++)
{
- char escape=0;
+ char escape= 0;
#ifdef USE_MB
int tmp_length;
if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
{
if (to + tmp_length > to_end)
{
- overflow=1;
+ overflow= TRUE;
break;
}
while (tmp_length--)
@@ -636,7 +655,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
{
if (to + 2 > to_end)
{
- overflow=1;
+ overflow= TRUE;
break;
}
*to++= '\\';
@@ -646,7 +665,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
{
if (to + 1 > to_end)
{
- overflow=1;
+ overflow= TRUE;
break;
}
*to++= *from;
@@ -656,3 +675,84 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
return overflow ? (ulong)~0 : (ulong) (to - to_start);
}
+
+/*
+ Escape apostrophes by doubling them up
+
+ SYNOPSIS
+ escape_quotes_for_mysql()
+ charset_info Charset of the strings
+ to Buffer for escaped string
+ to_length Length of destination buffer, or 0
+ from The string to escape
+ length The length of the string to escape
+
+ DESCRIPTION
+ This escapes the contents of a string by doubling up any apostrophes that
+ it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in
+ effect on the server.
+
+ NOTE
+ To be consistent with escape_string_for_mysql(), to_length may be 0 to
+ mean "big enough"
+
+ RETURN VALUES
+ ~0 The escaped string did not fit in the to buffer
+ >=0 The length of the escaped string
+*/
+ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info,
+ char *to, ulong to_length,
+ const char *from, ulong length)
+{
+ const char *to_start= to;
+ const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
+ my_bool overflow= FALSE;
+#ifdef USE_MB
+ my_bool use_mb_flag= use_mb(charset_info);
+#endif
+ for (end= from + length; from < end; from++)
+ {
+ char escape= 0;
+#ifdef USE_MB
+ int tmp_length;
+ if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
+ {
+ if (to + tmp_length > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ while (tmp_length--)
+ *to++= *from++;
+ from--;
+ continue;
+ }
+ /*
+ We don't have the same issue here with a non-multi-byte character being
+ turned into a multi-byte character by the addition of an escaping
+ character, because we are only escaping the ' character with itself.
+ */
+#endif
+ if (*from == '\'')
+ {
+ if (to + 2 > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ *to++= '\'';
+ *to++= '\'';
+ }
+ else
+ {
+ if (to + 1 > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ *to++= *from;
+ }
+ }
+ *to= 0;
+ return overflow ? (ulong)~0 : (ulong) (to - to_start);
+}
diff --git a/mysys/default.c b/mysys/default.c
index cffd57c37f1..15c92e816a6 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -31,6 +31,7 @@
--defaults-file=full-path-to-default-file ; Only this file will be read.
--defaults-extra-file=full-path-to-default-file ; Read this file before ~/
--print-defaults ; Print the modified command line and exit
+ --instance ; also read groups with concat(group, instance)
****************************************************************************/
#include "mysys_priv.h"
@@ -41,17 +42,20 @@
#include <winbase.h>
#endif
+const char *defaults_instance=0;
+static const char instance_option[] = "--instance=";
char *defaults_extra_file=0;
/* Which directories are searched for options (and in which order) */
-#define MAX_DEFAULT_DIRS 5
+#define MAX_DEFAULT_DIRS 6
const char *default_directories[MAX_DEFAULT_DIRS + 1];
#ifdef __WIN__
static const char *f_extensions[]= { ".ini", ".cnf", 0 };
#define NEWLINE "\r\n"
-static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN];
+static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN],
+ config_dir[FN_REFLEN];
#else
static const char *f_extensions[]= { ".cnf", 0 };
#define NEWLINE "\n"
@@ -115,7 +119,7 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv,
DBUG_ENTER("my_search_option_files");
/* Check if we want to force the use a specific default file */
- get_defaults_files(*argc, *argv,
+ get_defaults_files(*argc - *args_used, *argv + *args_used,
(char **)&forced_default_file,
(char **)&forced_extra_defaults);
if (forced_default_file)
@@ -283,8 +287,8 @@ int load_defaults(const char *conf_file, const char **groups,
{
DYNAMIC_ARRAY args;
TYPELIB group;
- my_bool found_print_defaults=0;
- uint args_used=0;
+ my_bool found_print_defaults= 0;
+ uint args_used= 0;
int error= 0;
MEM_ROOT alloc;
char *ptr,**res;
@@ -325,6 +329,49 @@ int load_defaults(const char *conf_file, const char **groups,
ctx.args= &args;
ctx.group= &group;
+ if (*argc >= 2 &&
+ is_prefix(argv[0][1], instance_option))
+ {
+ args_used++;
+ defaults_instance= argv[0][args_used]+sizeof(instance_option)-1;
+ }
+ else
+ {
+ defaults_instance= getenv("MYSQL_INSTANCE");
+ }
+
+ if (defaults_instance)
+ {
+ /** Handle --instance= */
+ uint i, len;
+ const char **extra_groups;
+ const uint instance_len= strlen(defaults_instance);
+
+ if (!(extra_groups=
+ (const char**)alloc_root(&alloc, (2*group.count+1)*sizeof(char*))))
+ goto err;
+
+ for (i= 0; i<group.count; i++)
+ {
+ extra_groups[i]= group.type_names[i]; /** copy group */
+
+ len= strlen(extra_groups[i]);
+ if (!(ptr= alloc_root(&alloc, len+instance_len+1)))
+ goto err;
+
+ extra_groups[i+group.count]= ptr;
+
+ /** Construct new group */
+ memcpy(ptr, extra_groups[i], len);
+ ptr+= len;
+ memcpy(ptr, defaults_instance, instance_len+1);
+ }
+
+ group.count*= 2;
+ group.type_names= extra_groups;
+ group.type_names[group.count]= 0;
+ }
+
error= my_search_option_files(conf_file, argc, argv, &args_used,
handle_default_option, (void *) &ctx);
/*
@@ -794,6 +841,7 @@ void my_print_default_files(const char *conf_file)
void print_defaults(const char *conf_file, const char **groups)
{
+ const char **groups_save= groups;
my_print_default_files(conf_file);
fputs("The following groups are read:",stdout);
@@ -802,6 +850,17 @@ void print_defaults(const char *conf_file, const char **groups)
fputc(' ',stdout);
fputs(*groups,stdout);
}
+
+ if (defaults_instance)
+ {
+ groups= groups_save;
+ for ( ; *groups ; groups++)
+ {
+ fputc(' ',stdout);
+ fputs(*groups,stdout);
+ fputs(defaults_instance,stdout);
+ }
+ }
puts("\nThe following options may be given as the first argument:\n\
--print-defaults Print the program argument list and exit\n\
--no-defaults Don't read default options from any options file\n\
@@ -812,6 +871,45 @@ void print_defaults(const char *conf_file, const char **groups)
#include <help_end.h>
+#ifdef __WIN__
+/*
+ This wrapper for GetSystemWindowsDirectory() will dynamically bind to the
+ function if it is available, emulate it on NT4 Terminal Server by stripping
+ the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just
+ return GetSystemDirectory().
+ */
+
+typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
+
+static uint my_get_system_windows_directory(char *buffer, uint size)
+{
+ GET_SYSTEM_WINDOWS_DIRECTORY
+ func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
+ GetProcAddress(GetModuleHandle("kernel32.dll"),
+ "GetSystemWindowsDirectoryA");
+
+ if (func_ptr)
+ return func_ptr(buffer, size);
+ else
+ {
+ /*
+ Windows NT 4.0 Terminal Server Edition:
+ To retrieve the shared Windows directory, call GetSystemDirectory and
+ trim the "System32" element from the end of the returned path.
+ */
+ UINT count= GetSystemDirectory(buffer, size);
+
+ if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0)
+ {
+ count-= 8;
+ buffer[count] = '\0';
+ }
+ return count;
+ }
+}
+#endif
+
+
/*
Create the list of default directories.
@@ -820,7 +918,8 @@ void print_defaults(const char *conf_file, const char **groups)
2. GetWindowsDirectory()
3. GetSystemWindowsDirectory()
4. getenv(DEFAULT_HOME_ENV)
- 5. ""
+ 5. Direcotry above where the executable is located
+ 6. ""
On Novell NetWare, this is:
1. sys:/etc/
@@ -851,13 +950,10 @@ static void init_default_directories()
if (GetWindowsDirectory(system_dir,sizeof(system_dir)))
*ptr++= (char*)&system_dir;
-#if defined(_MSC_VER) && (_MSC_VER >= 1300)
- /* Only VC7 and up */
- /* Only add shared system directory if different from default. */
- if (GetSystemWindowsDirectory(shared_system_dir,sizeof(shared_system_dir)) &&
+ if (my_get_system_windows_directory(shared_system_dir,
+ sizeof(shared_system_dir)) &&
strcmp(system_dir, shared_system_dir))
*ptr++= (char *)&shared_system_dir;
-#endif
#elif defined(__NETWARE__)
*ptr++= "sys:/etc/";
@@ -873,6 +969,36 @@ static void init_default_directories()
*ptr++= ""; /* Place for defaults_extra_file */
#if !defined(__WIN__) && !defined(__NETWARE__)
*ptr++= "~/";;
+#elif defined(__WIN__)
+ if (GetModuleFileName(NULL, config_dir, sizeof(config_dir)))
+ {
+ char *last= NULL, *end= strend(config_dir);
+ /*
+ Look for the second-to-last \ in the filename, but hang on
+ to a pointer after the last \ in case we're in the root of
+ a drive.
+ */
+ for ( ; end > config_dir; end--)
+ {
+ if (*end == FN_LIBCHAR)
+ {
+ if (last)
+ break;
+ last= end;
+ }
+ }
+
+ if (last)
+ {
+ if (end != config_dir && end[-1] == FN_DEVCHAR) /* Ended up with D:\ */
+ end[1]= 0; /* Keep one \ */
+ else if (end != config_dir)
+ end[0]= 0;
+ else
+ last[1]= 0;
+ }
+ *ptr++= (char *)&config_dir;
+ }
#endif
*ptr= 0; /* end marker */
}
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index fe784c7a44b..ea384f9f27a 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -1,3 +1,40 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "my_global.h"
+#include "mysys_priv.h"
+#include "m_string.h"
+#include <my_dir.h>
+
+#define BUFF_SIZE 1024
+/* should be big enough to handle at least one line */
+#define RESERVE 1024
+
+#ifdef __WIN__
+#define NEWLINE "\r\n"
+#define NEWLINE_LEN 2
+#else
+#define NEWLINE "\n"
+#define NEWLINE_LEN 1
+#endif
+
+static char *add_option(char *dst, const char *option_value,
+ const char *option, int remove_option);
+
+
/*
Add/remove option to the option file section.
@@ -15,6 +52,8 @@
into a buffer. Then we look for the option within this section and
change/remove it. In the end we get a buffer with modified version of the
file. Then we write it to the file, truncate it if needed and close it.
+ Note that there is a small time gap, when the file is incomplete,
+ and this theoretically might introduce a problem.
RETURN
0 - ok
@@ -22,24 +61,6 @@
2 - cannot open the file
*/
-#include "my_global.h"
-#include "mysys_priv.h"
-#include "m_string.h"
-#include <my_dir.h>
-
-#define BUFF_SIZE 1024
-
-#ifdef __WIN__
-#define NEWLINE "\r\n"
-#define NEWLINE_LEN 2
-#else
-#define NEWLINE "\n"
-#define NEWLINE_LEN 1
-#endif
-
-static char *add_option(char *dst, const char *option_value,
- const char *option, int remove_option);
-
int modify_defaults_file(const char *file_location, const char *option,
const char *option_value,
const char *section_name, int remove_option)
@@ -47,8 +68,11 @@ int modify_defaults_file(const char *file_location, const char *option,
FILE *cnf_file;
MY_STAT file_stat;
char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
- uint optlen, optval_len, sect_len, nr_newlines= 0;
+ uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size;
my_bool in_section= FALSE, opt_applied= 0;
+ uint reserve_extended= 1, old_opt_len= 0;
+ uint new_opt_len;
+ int reserve_occupied= 0;
DBUG_ENTER("modify_defaults_file");
if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0))))
@@ -56,27 +80,33 @@ int modify_defaults_file(const char *file_location, const char *option,
/* my_fstat doesn't use the flag parameter */
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
- goto err;
+ goto malloc_err;
- optlen= (uint) strlen(option);
+ opt_len= (uint) strlen(option);
optval_len= (uint) strlen(option_value);
+ new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
+
+ /* calculate the size of the buffer we need */
+ buffer_size= sizeof(char) * (file_stat.st_size +
+ /* option name len */
+ opt_len +
+ /* reserve for '=' char */
+ 1 +
+ /* option value len */
+ optval_len +
+ /* reserve space for newline */
+ NEWLINE_LEN +
+ /* The ending zero */
+ 1 +
+ /* reserve some additional space */
+ RESERVE);
+
/*
Reserve space to read the contents of the file and some more
for the option we want to add.
*/
- if (!(file_buffer= (char*) my_malloc(sizeof(char) *
- (file_stat.st_size +
- /* option name len */
- optlen +
- /* reserve space for newline */
- NEWLINE_LEN +
- /* reserve for '=' char */
- 1 +
- /* option value len */
- optval_len +
- /* The ending zero plus some safety */
- FN_REFLEN), MYF(MY_WME))))
+ if (!(file_buffer= (char*) my_malloc(buffer_size, MYF(MY_WME))))
goto malloc_err;
sect_len= (uint) strlen(section_name);
@@ -94,24 +124,50 @@ int modify_defaults_file(const char *file_location, const char *option,
continue;
}
- if (!opt_applied && in_section && !strncmp(src_ptr, option, optlen) &&
- (*(src_ptr + optlen) == '=' ||
- my_isspace(&my_charset_latin1, *(src_ptr + optlen)) ||
- *(src_ptr + optlen) == '\0'))
+ /* correct the option */
+ if (in_section && !strncmp(src_ptr, option, opt_len) &&
+ (*(src_ptr + opt_len) == '=' ||
+ my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
+ *(src_ptr + opt_len) == '\0'))
{
+ /*
+ we should change all options. If opt_applied is set, we are running
+ into reserved memory area. Hence we should check for overruns.
+ */
+ if (opt_applied)
+ {
+ src_ptr+= opt_len; /* If we correct an option, we know it's name */
+ old_opt_len= opt_len;
+
+ while (*src_ptr++) /* Find the end of the line */
+ old_opt_len++;
+
+ /* could be negative */
+ reserve_occupied+= (int) new_opt_len - (int) old_opt_len;
+ if ((int) reserve_occupied > (int) (RESERVE*reserve_extended))
+ {
+ if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size +
+ RESERVE*reserve_extended,
+ MYF(MY_WME|MY_FREE_ON_ERROR))))
+ goto malloc_err;
+ reserve_extended++;
+ }
+ }
+ else
+ opt_applied= 1;
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
- opt_applied= 1;
}
else
{
/* If going to new group and we have option to apply, do it now */
if (in_section && !opt_applied && *src_ptr == '[')
{
- dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
-
+ dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
+ opt_applied= 1; /* set the flag to do write() later */
}
+
for (; nr_newlines; nr_newlines--)
- dst_ptr= strmov(dst_ptr, NEWLINE);
+ dst_ptr= strmov(dst_ptr, NEWLINE);
dst_ptr= strmov(dst_ptr, linebuff);
}
/* Look for a section */
@@ -120,13 +176,13 @@ int modify_defaults_file(const char *file_location, const char *option,
/* Copy the line to the buffer */
if (!strncmp(++src_ptr, section_name, sect_len))
{
- src_ptr+= sect_len;
- /* Skip over whitespaces. They are allowed after section name */
- for (; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++)
- {}
+ src_ptr+= sect_len;
+ /* Skip over whitespaces. They are allowed after section name */
+ for (; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++)
+ {}
- if (*src_ptr != ']')
- continue; /* Missing closing parenthesis. Assume this was no group */
+ if (*src_ptr != ']')
+ continue; /* Missing closing parenthesis. Assume this was no group */
in_section= TRUE;
}
else
@@ -149,10 +205,10 @@ int modify_defaults_file(const char *file_location, const char *option,
{
/* Don't write the file if there are no changes to be made */
if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
- MYF(MY_WME)) ||
- my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
- my_fwrite(cnf_file, file_buffer, (uint) (dst_ptr - file_buffer),
- MYF(MY_NABP)))
+ MYF(MY_WME)) ||
+ my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
+ my_fwrite(cnf_file, file_buffer, (uint) (dst_ptr - file_buffer),
+ MYF(MY_NABP)))
goto err;
}
if (my_fclose(cnf_file, MYF(MY_WME)))
diff --git a/mysys/hash.c b/mysys/hash.c
index 28f8797288c..45cf7d5ff1d 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -277,9 +277,8 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
record being compared against.
RETURN
- < 0 key of record < key
= 0 key of record == key
- > 0 key of record > key
+ != 0 key of record != key
*/
static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 28210bdfc7d..256749ed447 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -93,20 +93,21 @@ int check_if_legal_filename(const char *path)
path+= dirname_length(path); /* To start of filename */
if (!(end= strchr(path, FN_EXTCHAR)))
end= strend(path);
- if (path == end || (uint) (path - end) > MAX_RESERVED_NAME_LENGTH)
+ if (path == end || (uint) (end - path) > MAX_RESERVED_NAME_LENGTH)
DBUG_RETURN(0); /* Simplify inner loop */
for (reserved_name= reserved_names; *reserved_name; reserved_name++)
{
+ const char *reserved= *reserved_name; /* never empty */
const char *name= path;
- while (name != end)
+
+ do
{
- if (my_toupper(&my_charset_latin1, *path) !=
- my_toupper(&my_charset_latin1, *name))
+ if (*reserved != my_toupper(&my_charset_latin1, *name))
break;
- if (name++ == end)
+ if (++name == end)
DBUG_RETURN(1); /* Found wrong path */
- }
+ } while (*++reserved);
}
DBUG_RETURN(0);
}
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index c0eb6f15548..ba958b234d2 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -109,6 +109,51 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
}
+/*
+ test if bit already set and set it if it was not (thread unsafe method)
+
+ SYNOPSIS
+ bitmap_fast_test_and_set()
+ MAP bit map struct
+ BIT bit number
+
+ RETURN
+ 0 bit was not set
+ !=0 bit was set
+*/
+
+my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
+{
+ uchar *byte= map->bitmap + (bitmap_bit / 8);
+ uchar bit= 1 << ((bitmap_bit) & 7);
+ uchar res= (*byte) & bit;
+ *byte|= bit;
+ return res;
+}
+
+
+/*
+ test if bit already set and set it if it was not (thread safe method)
+
+ SYNOPSIS
+ bitmap_fast_test_and_set()
+ map bit map struct
+ bitmap_bit bit number
+
+ RETURN
+ 0 bit was not set
+ !=0 bit was set
+*/
+
+my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
+{
+ my_bool res;
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
+ bitmap_lock(map);
+ res= bitmap_fast_test_and_set(map, bitmap_bit);
+ bitmap_unlock(map);
+}
+
uint bitmap_set_next(MY_BITMAP *map)
{
uchar *bitmap=map->bitmap;
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 03f3feb54d3..072492172e3 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -16,7 +16,7 @@
#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
-#include <sys/stat.h>
+#include <my_dir.h> /* for stat */
#include <m_string.h>
#if defined(HAVE_UTIME_H)
#include <utime.h>
@@ -53,26 +53,28 @@ struct utimbuf {
int my_copy(const char *from, const char *to, myf MyFlags)
{
uint Count;
- int new_file_stat, create_flag;
+ my_bool new_file_stat; /* 1 if we could stat "to" */
+ int create_flag;
File from_file,to_file;
char buff[IO_SIZE];
- struct stat stat_buff,new_stat_buff;
+ MY_STAT stat_buff,new_stat_buff;
DBUG_ENTER("my_copy");
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
from_file=to_file= -1;
- new_file_stat=0;
+ LINT_INIT(new_file_stat);
+ DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
- new_file_stat=stat((char*) to, &new_stat_buff);
+ new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));
if ((from_file=my_open(from,O_RDONLY | O_SHARE,MyFlags)) >= 0)
{
- if (stat(from,&stat_buff))
+ if (!my_stat(from, &stat_buff, MyFlags))
{
my_errno=errno;
goto err;
}
- if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
stat_buff=new_stat_buff;
create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC;
@@ -91,7 +93,7 @@ int my_copy(const char *from, const char *to, myf MyFlags)
/* Copy modes if possible */
- if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
DBUG_RETURN(0); /* File copyed but not stat */
VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */
#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) && !defined(__NETWARE__)
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index 002e5ca0f06..f07beec9f39 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -19,27 +19,36 @@
#include <errno.h>
#include "mysys_err.h"
-static void make_ftype(my_string to,int flag);
+static void make_ftype(my_string to,int flag);
- /* Open a file as stream */
+/*
+ Open a file as stream
-FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
- /* Path-name of file */
- /* Read | write .. */
- /* Special flags */
+ SYNOPSIS
+ my_fopen()
+ FileName Path-name of file
+ Flags Read | write | append | trunc (like for open())
+ MyFlags Flags for handling errors
+
+ RETURN
+ 0 Error
+ # File handler
+*/
+
+FILE *my_fopen(const char *filename, int flags, myf MyFlags)
{
FILE *fd;
char type[5];
DBUG_ENTER("my_fopen");
- DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
- FileName, Flags, MyFlags));
+ DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
+ filename, flags, MyFlags));
/*
if we are not creating, then we need to use my_access to make sure
the file exists since Windows doesn't handle files like "com1.sym"
very well
*/
#ifdef __WIN__
- if (check_if_legal_filename(FileName))
+ if (check_if_legal_filename(filename))
{
errno= EACCES;
fd= 0;
@@ -47,8 +56,8 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
else
#endif
{
- make_ftype(type,Flags);
- fd = fopen(FileName, type);
+ make_ftype(type,flags);
+ fd = fopen(filename, type);
}
if (fd != 0)
@@ -65,7 +74,7 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
}
pthread_mutex_lock(&THR_LOCK_open);
if ((my_file_info[fileno(fd)].name = (char*)
- my_strdup(FileName,MyFlags)))
+ my_strdup(filename,MyFlags)))
{
my_stream_opened++;
my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
@@ -81,9 +90,9 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
my_errno=errno;
DBUG_PRINT("error",("Got error %d on open",my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
- my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND :
+ my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND :
EE_CANTCREATEFILE,
- MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ MYF(ME_BELL+ME_WAITTANG), filename, my_errno);
DBUG_RETURN((FILE*) 0);
} /* my_fopen */
@@ -158,33 +167,39 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
DBUG_RETURN(fd);
} /* my_fdopen */
+
/*
- make_ftype
- Make a filehandler-open-typestring from ordinary inputflags
+ Make a fopen() typestring from a open() type bitmap
+
+ SYNOPSIS
+ make_ftype()
+ to String for fopen() is stored here
+ flag Flag used by open()
- Note: This routine attempts to find the best possible match
- between a numeric option and a string option that could be
- fed to fopen. There is not a 1 to 1 mapping between the two.
+ IMPLEMENTATION
+ This routine attempts to find the best possible match
+ between a numeric option and a string option that could be
+ fed to fopen. There is not a 1 to 1 mapping between the two.
- r == O_RDONLY
- w == O_WRONLY|O_TRUNC|O_CREAT
- a == O_WRONLY|O_APPEND|O_CREAT
- r+ == O_RDWR
- w+ == O_RDWR|O_TRUNC|O_CREAT
- a+ == O_RDWR|O_APPEND|O_CREAT
+ NOTE
+ On Unix, O_RDONLY is usually 0
+
+ MAPPING
+ r == O_RDONLY
+ w == O_WRONLY|O_TRUNC|O_CREAT
+ a == O_WRONLY|O_APPEND|O_CREAT
+ r+ == O_RDWR
+ w+ == O_RDWR|O_TRUNC|O_CREAT
+ a+ == O_RDWR|O_APPEND|O_CREAT
*/
+
static void make_ftype(register my_string to, register int flag)
{
-#if FILE_BINARY
- /* If we have binary-files */
- reg3 int org_flag=flag;
-#endif
- flag&= ~FILE_BINARY; /* remove binary bit */
-
/* check some possible invalid combinations */
- DBUG_ASSERT(flag & (O_TRUNC|O_APPEND) != O_TRUNC|O_APPEND);
+ DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND));
+ DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR));
- if (flag & (O_RDONLY|O_WRONLY) == O_WRONLY)
+ if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY)
*to++= (flag & O_APPEND) ? 'a' : 'w';
else if (flag & O_RDWR)
{
@@ -201,9 +216,8 @@ static void make_ftype(register my_string to, register int flag)
*to++= 'r';
#if FILE_BINARY /* If we have binary-files */
- if (org_flag & FILE_BINARY)
+ if (flag & FILE_BINARY)
*to++='b';
#endif
*to='\0';
} /* make_ftype */
-
diff --git a/mysys/my_os2cond.c b/mysys/my_os2cond.c
index e23afb89e66..83a03d62046 100644
--- a/mysys/my_os2cond.c
+++ b/mysys/my_os2cond.c
@@ -100,7 +100,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
rc = DosWaitEventSem(cond->semaphore, timeout);
if (rc != 0)
- rval = ETIME;
+ rval= ETIMEDOUT;
if (mutex) pthread_mutex_lock(mutex);
diff --git a/mysys/tree.c b/mysys/tree.c
index bec1ec680f1..1780913961e 100644
--- a/mysys/tree.c
+++ b/mysys/tree.c
@@ -263,6 +263,9 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size,
if (tree->flag & TREE_NO_DUPS)
return(NULL);
element->count++;
+ /* Avoid a wrap over of the count. */
+ if (! element->count)
+ element->count--;
}
DBUG_EXECUTE("check_tree", test_rb_tree(tree->root););
return element;
diff --git a/ndb/include/kernel/AttributeList.hpp b/ndb/include/kernel/AttributeList.hpp
index 7c6f71df3d2..70b178c6c79 100644
--- a/ndb/include/kernel/AttributeList.hpp
+++ b/ndb/include/kernel/AttributeList.hpp
@@ -17,6 +17,8 @@
#ifndef ATTRIBUTE_LIST_HPP
#define ATTRIBUTE_LIST_HPP
+#include "ndb_limits.h"
+
/**
* Masks and lists used by index and trigger. Must be plain old Uint32 data.
* XXX depends on other headers XXX move to some common file
diff --git a/ndb/include/mgmcommon/ConfigRetriever.hpp b/ndb/include/mgmcommon/ConfigRetriever.hpp
index 95d257dea23..c0b877af07d 100644
--- a/ndb/include/mgmcommon/ConfigRetriever.hpp
+++ b/ndb/include/mgmcommon/ConfigRetriever.hpp
@@ -32,6 +32,7 @@ public:
~ConfigRetriever();
int do_connect(int no_retries, int retry_delay_in_seconds, int verbose);
+ int disconnect();
/**
* Get configuration for current node.
diff --git a/ndb/include/ndb_version.h.in b/ndb/include/ndb_version.h.in
index d7f43eae40a..826f5124407 100644
--- a/ndb/include/ndb_version.h.in
+++ b/ndb/include/ndb_version.h.in
@@ -36,8 +36,16 @@
#define MAKE_VERSION(A,B,C) (((A) << 16) | ((B) << 8) | ((C) << 0))
#define NDB_VERSION_D MAKE_VERSION(NDB_VERSION_MAJOR, NDB_VERSION_MINOR, NDB_VERSION_BUILD)
-
-#define NDB_VERSION_STRING (getVersionString(NDB_VERSION, NDB_VERSION_STATUS))
+#define NDB_VERSION_STRING_BUF_SZ 100
+#ifdef __cplusplus
+extern "C"
+#else
+extern
+#endif
+char ndb_version_string_buf[NDB_VERSION_STRING_BUF_SZ];
+#define NDB_VERSION_STRING (getVersionString(NDB_VERSION, NDB_VERSION_STATUS, \
+ ndb_version_string_buf, \
+ sizeof(ndb_version_string_buf)))
#define NDB_VERSION ndbGetOwnVersion()
diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp
index a36cdc2b475..db2212075e8 100644
--- a/ndb/include/ndbapi/Ndb.hpp
+++ b/ndb/include/ndbapi/Ndb.hpp
@@ -1583,15 +1583,17 @@ private:
void abortTransactionsAfterNodeFailure(Uint16 aNodeId);
static
- const char * externalizeTableName(const char * internalTableName, bool fullyQualifiedNames);
+ const char * externalizeTableName(const char * internalTableName,
+ bool fullyQualifiedNames);
const char * externalizeTableName(const char * internalTableName);
- const char * internalizeTableName(const char * externalTableName);
+ const BaseString internalize_table_name(const char * external_name) const;
static
- const char * externalizeIndexName(const char * internalIndexName, bool fullyQualifiedNames);
+ const char * externalizeIndexName(const char * internalIndexName,
+ bool fullyQualifiedNames);
const char * externalizeIndexName(const char * internalIndexName);
- const char * internalizeIndexName(const NdbTableImpl * table,
- const char * externalIndexName);
+ const BaseString internalize_index_name(const NdbTableImpl * table,
+ const char * external_name) const;
static
const BaseString getDatabaseFromInternalName(const char * internalName);
@@ -1614,7 +1616,7 @@ private:
Uint32 theNoOfPreparedTransactions;
Uint32 theNoOfSentTransactions;
Uint32 theNoOfCompletedTransactions;
- Uint32 theNoOfAllocatedTransactions;
+ Uint32 theRemainingStartTransactions;
Uint32 theMaxNoOfTransactions;
Uint32 theMinNoOfEventsToWakeUp;
diff --git a/ndb/include/portlib/NdbTCP.h b/ndb/include/portlib/NdbTCP.h
index 8138a2ef354..308a3833ffd 100644
--- a/ndb/include/portlib/NdbTCP.h
+++ b/ndb/include/portlib/NdbTCP.h
@@ -31,7 +31,7 @@
#define NDB_NONBLOCK FNDELAY
#define NDB_SOCKET_TYPE int
#define NDB_INVALID_SOCKET -1
-#define NDB_CLOSE_SOCKET(x) close(x)
+#define _NDB_CLOSE_SOCKET(x) close(x)
/**
* socklen_t not defined in the header files of OSE
@@ -52,7 +52,7 @@ typedef int socklen_t;
#define EWOULDBLOCK WSAEWOULDBLOCK
#define NDB_SOCKET_TYPE SOCKET
#define NDB_INVALID_SOCKET INVALID_SOCKET
-#define NDB_CLOSE_SOCKET(x) closesocket(x)
+#define _NDB_CLOSE_SOCKET(x) closesocket(x)
#else
@@ -64,7 +64,7 @@ typedef int socklen_t;
#define NDB_NONBLOCK O_NONBLOCK
#define NDB_SOCKET_TYPE int
#define NDB_INVALID_SOCKET -1
-#define NDB_CLOSE_SOCKET(x) ::close(x)
+#define _NDB_CLOSE_SOCKET(x) ::close(x)
#define InetErrno errno
@@ -89,6 +89,12 @@ extern "C" {
*/
int Ndb_getInAddr(struct in_addr * dst, const char *address);
+#ifdef DBUG_OFF
+#define NDB_CLOSE_SOCKET(fd) _NDB_CLOSE_SOCKET(fd)
+#else
+int NDB_CLOSE_SOCKET(int fd);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/ndb/include/transporter/TransporterDefinitions.hpp b/ndb/include/transporter/TransporterDefinitions.hpp
index 8fc407b6d9c..e9c5ffa2c80 100644
--- a/ndb/include/transporter/TransporterDefinitions.hpp
+++ b/ndb/include/transporter/TransporterDefinitions.hpp
@@ -45,9 +45,8 @@ enum SendStatus {
* Protocol6 Header +
* (optional signal id) + (optional checksum) + (signal data)
*/
-const Uint32 MAX_SECTION_SIZE= 4096;
//const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25));
-const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*MAX_SECTION_SIZE);
+const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*4096);
/**
* TransporterConfiguration
diff --git a/ndb/include/transporter/TransporterRegistry.hpp b/ndb/include/transporter/TransporterRegistry.hpp
index 1ae8a4068c4..0bb9733e8c4 100644
--- a/ndb/include/transporter/TransporterRegistry.hpp
+++ b/ndb/include/transporter/TransporterRegistry.hpp
@@ -268,6 +268,8 @@ public:
Transporter* get_transporter(NodeId nodeId);
NodeId get_localNodeId() { return localNodeId; };
+
+ struct in_addr get_connect_address(NodeId node_id) const;
protected:
private:
diff --git a/ndb/include/util/SimpleProperties.hpp b/ndb/include/util/SimpleProperties.hpp
index 356f3406f38..438426fb62b 100644
--- a/ndb/include/util/SimpleProperties.hpp
+++ b/ndb/include/util/SimpleProperties.hpp
@@ -172,6 +172,8 @@ public:
virtual bool reset() = 0;
virtual bool putWord(Uint32 val) = 0;
virtual bool putWords(const Uint32 * src, Uint32 len) = 0;
+ private:
+ bool add(const char* value, int len);
};
};
@@ -211,7 +213,7 @@ private:
};
/**
- * Writer for linear memory
+ * Writer for UtilBuffer
*/
class UtilBufferWriter : public SimpleProperties::Writer {
public:
diff --git a/ndb/include/util/SocketServer.hpp b/ndb/include/util/SocketServer.hpp
index 2e1afb74945..4c37e63adf0 100644
--- a/ndb/include/util/SocketServer.hpp
+++ b/ndb/include/util/SocketServer.hpp
@@ -41,7 +41,13 @@ public:
protected:
friend class SocketServer;
friend void* sessionThread_C(void*);
- Session(NDB_SOCKET_TYPE sock): m_socket(sock){ m_stop = m_stopped = false;}
+ Session(NDB_SOCKET_TYPE sock): m_socket(sock)
+ {
+ DBUG_ENTER("SocketServer::Session");
+ DBUG_PRINT("enter",("NDB_SOCKET: %d", m_socket));
+ m_stop = m_stopped = false;
+ DBUG_VOID_RETURN;
+ }
bool m_stop; // Has the session been ordered to stop?
bool m_stopped; // Has the session stopped?
diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h
index 72abd6d5d7a..f60ac4e6a63 100644
--- a/ndb/include/util/ndb_opts.h
+++ b/ndb/include/util/ndb_opts.h
@@ -28,6 +28,7 @@
my_bool opt_ndb_optimized_node_selection
int opt_ndb_nodeid;
+bool opt_endinfo= 0;
my_bool opt_ndb_shm;
const char *opt_ndb_connectstring= 0;
const char *opt_connect_str= 0;
@@ -119,6 +120,7 @@ ndb_std_get_one_option(int optid,
{
DBUG_PUSH("d:t");
}
+ opt_endinfo= 1;
break;
#endif
case 'V':
diff --git a/ndb/include/util/version.h b/ndb/include/util/version.h
index 5459e44b818..62dc07d905a 100644
--- a/ndb/include/util/version.h
+++ b/ndb/include/util/version.h
@@ -30,7 +30,8 @@ extern "C" {
Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build);
- const char* getVersionString(Uint32 version, const char * status);
+ const char* getVersionString(Uint32 version, const char * status,
+ char *buf, unsigned sz);
void ndbPrintVersion();
Uint32 ndbGetOwnVersion();
diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp
index ec4137297f1..a9d4512112f 100644
--- a/ndb/src/common/logger/LogHandler.cpp
+++ b/ndb/src/common/logger/LogHandler.cpp
@@ -31,6 +31,7 @@ LogHandler::LogHandler() :
m_last_message[0]= 0;
m_last_log_time= 0;
m_now= 0;
+ m_last_level= (Logger::LoggerLevel)-1;
}
LogHandler::~LogHandler()
diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp
index eca886c8586..b3d0221fedb 100644
--- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp
+++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp
@@ -47,6 +47,8 @@
ConfigRetriever::ConfigRetriever(const char * _connect_string,
Uint32 version, Uint32 node_type)
{
+ DBUG_ENTER("ConfigRetriever::ConfigRetriever");
+
m_version = version;
m_node_type = node_type;
_ownNodeId= 0;
@@ -55,23 +57,26 @@ ConfigRetriever::ConfigRetriever(const char * _connect_string,
if (m_handle == 0) {
setError(CR_ERROR, "Unable to allocate mgm handle");
- return;
+ DBUG_VOID_RETURN;
}
if (ndb_mgm_set_connectstring(m_handle, _connect_string))
{
setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle));
- return;
+ DBUG_VOID_RETURN;
}
resetError();
+ DBUG_VOID_RETURN;
}
ConfigRetriever::~ConfigRetriever()
{
+ DBUG_ENTER("ConfigRetriever::~ConfigRetriever");
if (m_handle) {
ndb_mgm_disconnect(m_handle);
ndb_mgm_destroy_handle(&m_handle);
}
+ DBUG_VOID_RETURN;
}
Uint32
@@ -107,6 +112,12 @@ ConfigRetriever::do_connect(int no_retries,
0 : -1;
}
+int
+ConfigRetriever::disconnect()
+{
+ return ndb_mgm_disconnect(m_handle);
+}
+
//****************************************************************************
//****************************************************************************
//****************************************************************************
@@ -131,14 +142,14 @@ ConfigRetriever::getConfig() {
}
ndb_mgm_configuration *
-ConfigRetriever::getConfig(NdbMgmHandle m_handle){
-
+ConfigRetriever::getConfig(NdbMgmHandle m_handle)
+{
ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_handle,m_version);
- if(conf == 0){
+ if(conf == 0)
+ {
setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle));
return 0;
}
-
return conf;
}
diff --git a/ndb/src/common/portlib/NdbMutex.c b/ndb/src/common/portlib/NdbMutex.c
index d3d39ea8cf7..4a170d87e5c 100644
--- a/ndb/src/common/portlib/NdbMutex.c
+++ b/ndb/src/common/portlib/NdbMutex.c
@@ -25,31 +25,35 @@ NdbMutex* NdbMutex_Create(void)
{
NdbMutex* pNdbMutex;
int result;
+ DBUG_ENTER("NdbMutex_Create");
pNdbMutex = (NdbMutex*)NdbMem_Allocate(sizeof(NdbMutex));
+ DBUG_PRINT("info",("NdbMem_Allocate 0x%lx",pNdbMutex));
if (pNdbMutex == NULL)
- return NULL;
+ DBUG_RETURN(NULL);
result = pthread_mutex_init(pNdbMutex, NULL);
assert(result == 0);
- return pNdbMutex;
-
+ DBUG_RETURN(pNdbMutex);
}
int NdbMutex_Destroy(NdbMutex* p_mutex)
{
int result;
+ DBUG_ENTER("NdbMutex_Destroy");
if (p_mutex == NULL)
- return -1;
+ DBUG_RETURN(-1);
result = pthread_mutex_destroy(p_mutex);
- free(p_mutex);
+
+ DBUG_PRINT("info",("NdbMem_Free 0x%lx",p_mutex));
+ NdbMem_Free(p_mutex);
- return result;
+ DBUG_RETURN(result);
}
diff --git a/ndb/src/common/portlib/NdbTCP.cpp b/ndb/src/common/portlib/NdbTCP.cpp
index a63f5a7ba27..c7b9d33c5f6 100644
--- a/ndb/src/common/portlib/NdbTCP.cpp
+++ b/ndb/src/common/portlib/NdbTCP.cpp
@@ -54,6 +54,15 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) {
return -1; //DBUG_RETURN(-1);
}
+#ifndef DBUG_OFF
+extern "C"
+int NDB_CLOSE_SOCKET(int fd)
+{
+ DBUG_PRINT("info", ("NDB_CLOSE_SOCKET(%d)", fd));
+ return _NDB_CLOSE_SOCKET(fd);
+}
+#endif
+
#if 0
int
Ndb_getInAddr(struct in_addr * dst, const char *address) {
diff --git a/ndb/src/common/portlib/NdbThread.c b/ndb/src/common/portlib/NdbThread.c
index aaee9b45069..55ebc4c8111 100644
--- a/ndb/src/common/portlib/NdbThread.c
+++ b/ndb/src/common/portlib/NdbThread.c
@@ -56,6 +56,7 @@ ndb_thread_wrapper(void* _ss){
void *ret;
struct NdbThread * ss = (struct NdbThread *)_ss;
ret= (* ss->func)(ss->object);
+ DBUG_POP();
NdbThread_Exit(ret);
}
/* will never be reached */
@@ -73,15 +74,18 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func,
struct NdbThread* tmpThread;
int result;
pthread_attr_t thread_attr;
+ DBUG_ENTER("NdbThread_Create");
(void)thread_prio; /* remove warning for unused parameter */
if (p_thread_func == NULL)
- return 0;
+ DBUG_RETURN(NULL);
tmpThread = (struct NdbThread*)NdbMem_Allocate(sizeof(struct NdbThread));
if (tmpThread == NULL)
- return NULL;
+ DBUG_RETURN(NULL);
+
+ DBUG_PRINT("info",("thread_name: %s", p_thread_name));
strnmov(tmpThread->thread_name,p_thread_name,sizeof(tmpThread->thread_name));
@@ -108,16 +112,20 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func,
assert(result==0);
pthread_attr_destroy(&thread_attr);
- return tmpThread;
+ DBUG_PRINT("exit",("ret: %lx", tmpThread));
+ DBUG_RETURN(tmpThread);
}
void NdbThread_Destroy(struct NdbThread** p_thread)
{
- if (*p_thread != NULL){
+ DBUG_ENTER("NdbThread_Destroy");
+ if (*p_thread != NULL){
+ DBUG_PRINT("enter",("*p_thread: %lx", * p_thread));
free(* p_thread);
* p_thread = 0;
}
+ DBUG_VOID_RETURN;
}
diff --git a/ndb/src/common/transporter/SCI_Transporter.cpp b/ndb/src/common/transporter/SCI_Transporter.cpp
index c96f84a4f4f..1fe276249e5 100644
--- a/ndb/src/common/transporter/SCI_Transporter.cpp
+++ b/ndb/src/common/transporter/SCI_Transporter.cpp
@@ -48,7 +48,7 @@ SCI_Transporter::SCI_Transporter(TransporterRegistry &t_reg,
Uint32 reportFreq) :
Transporter(t_reg, tt_SCI_TRANSPORTER,
lHostName, rHostName, r_port, isMgmConnection, _localNodeId,
- _remoteNodeId, serverNodeID, 0, false, chksm, signalId)
+ _remoteNodeId, serverNodeId, 0, false, chksm, signalId)
{
DBUG_ENTER("SCI_Transporter::SCI_Transporter");
m_PacketSize = (packetSize + 3)/4 ;
diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp
index 124ed5f7241..377fabe27ab 100644
--- a/ndb/src/common/transporter/Transporter.cpp
+++ b/ndb/src/common/transporter/Transporter.cpp
@@ -76,6 +76,7 @@ Transporter::Transporter(TransporterRegistry &t_reg,
m_connected = false;
m_timeOutMillis = 1000;
+ m_connect_address.s_addr= 0;
if(s_port<0)
s_port= -s_port; // was dynamic
@@ -103,6 +104,13 @@ Transporter::connect_server(NDB_SOCKET_TYPE sockfd) {
DBUG_RETURN(true); // TODO assert(0);
}
+ {
+ struct sockaddr addr;
+ SOCKET_SIZE_TYPE addrlen= sizeof(addr);
+ int r= getpeername(sockfd, &addr, &addrlen);
+ m_connect_address= ((struct sockaddr_in *)&addr)->sin_addr;
+ }
+
bool res = connect_server_impl(sockfd);
if(res){
m_connected = true;
@@ -189,6 +197,13 @@ Transporter::connect_client(NDB_SOCKET_TYPE sockfd) {
g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId);
}
+ {
+ struct sockaddr addr;
+ SOCKET_SIZE_TYPE addrlen= sizeof(addr);
+ int r= getpeername(sockfd, &addr, &addrlen);
+ m_connect_address= ((struct sockaddr_in *)&addr)->sin_addr;
+ }
+
bool res = connect_client_impl(sockfd);
if(res){
m_connected = true;
diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp
index 8c5e96226a3..c9f4e9bda42 100644
--- a/ndb/src/common/transporter/Transporter.hpp
+++ b/ndb/src/common/transporter/Transporter.hpp
@@ -147,6 +147,7 @@ private:
bool isMgmConnection;
SocketClient *m_socket_client;
+ struct in_addr m_connect_address;
protected:
Uint32 getErrorCount();
diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp
index 3776bce7452..60649665d4a 100644
--- a/ndb/src/common/transporter/TransporterRegistry.cpp
+++ b/ndb/src/common/transporter/TransporterRegistry.cpp
@@ -55,6 +55,12 @@ extern int g_ndb_shm_signum;
#include <EventLogger.hpp>
extern EventLogger g_eventLogger;
+struct in_addr
+TransporterRegistry::get_connect_address(NodeId node_id) const
+{
+ return theTransporters[node_id]->m_connect_address;
+}
+
SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd)
{
DBUG_ENTER("SocketServer::Session * TransporterService::newSession");
@@ -74,7 +80,9 @@ SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd)
TransporterRegistry::TransporterRegistry(void * callback,
unsigned _maxTransporters,
- unsigned sizeOfLongSignalMemory) {
+ unsigned sizeOfLongSignalMemory)
+{
+ DBUG_ENTER("TransporterRegistry::TransporterRegistry");
nodeIdSpecified = false;
maxTransporters = _maxTransporters;
@@ -112,6 +120,8 @@ TransporterRegistry::TransporterRegistry(void * callback,
theOSEReceiver = 0;
theOSEJunkSocketSend = 0;
theOSEJunkSocketRecv = 0;
+
+ DBUG_VOID_RETURN;
}
void TransporterRegistry::set_mgm_handle(NdbMgmHandle h)
@@ -135,7 +145,9 @@ void TransporterRegistry::set_mgm_handle(NdbMgmHandle h)
DBUG_VOID_RETURN;
}
-TransporterRegistry::~TransporterRegistry() {
+TransporterRegistry::~TransporterRegistry()
+{
+ DBUG_ENTER("TransporterRegistry::~TransporterRegistry");
removeAll();
@@ -157,6 +169,8 @@ TransporterRegistry::~TransporterRegistry() {
#endif
if (m_mgm_handle)
ndb_mgm_destroy_handle(&m_mgm_handle);
+
+ DBUG_VOID_RETURN;
}
void
diff --git a/ndb/src/common/util/Parser.cpp b/ndb/src/common/util/Parser.cpp
index dea128ccf66..d692aa18392 100644
--- a/ndb/src/common/util/Parser.cpp
+++ b/ndb/src/common/util/Parser.cpp
@@ -141,7 +141,10 @@ split(char * buf, char ** name, char ** value){
bool
ParserImpl::run(Context * ctx, const class Properties ** pDst,
- volatile bool * stop) const {
+ volatile bool * stop) const
+{
+ DBUG_ENTER("ParserImpl::run");
+
* pDst = 0;
bool ownStop = false;
if(stop == 0)
@@ -153,24 +156,24 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst,
ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
if(Eof(ctx->m_currentToken)){
ctx->m_status = Parser<Dummy>::Eof;
- return false;
+ DBUG_RETURN(false);
}
if(ctx->m_currentToken[0] == 0){
ctx->m_status = Parser<Dummy>::NoLine;
- return false;
+ DBUG_RETURN(false);
}
if(Empty(ctx->m_currentToken)){
ctx->m_status = Parser<Dummy>::EmptyLine;
- return false;
+ DBUG_RETURN(false);
}
trim(ctx->m_currentToken);
ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows);
if(ctx->m_currentCmd == 0){
ctx->m_status = Parser<Dummy>::UnknownCommand;
- return false;
+ DBUG_RETURN(false);
}
Properties * p = new Properties();
@@ -200,19 +203,19 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst,
tmp = input.gets(buf, sz);
} while((! * stop) && !Eof(tmp) && !Empty(tmp));
}
- return false;
+ DBUG_RETURN(false);
}
if(* stop){
delete p;
ctx->m_status = Parser<Dummy>::ExternalStop;
- return false;
+ DBUG_RETURN(false);
}
if(!checkMandatory(ctx, p)){
ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
delete p;
- return false;
+ DBUG_RETURN(false);
}
/**
@@ -229,7 +232,7 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst,
ctx->m_status = Parser<Dummy>::Ok;
* pDst = p;
- return true;
+ DBUG_RETURN(true);
}
const ParserImpl::DummyRow*
diff --git a/ndb/src/common/util/SimpleProperties.cpp b/ndb/src/common/util/SimpleProperties.cpp
index 00c440fcb4e..c25aaea491a 100644
--- a/ndb/src/common/util/SimpleProperties.cpp
+++ b/ndb/src/common/util/SimpleProperties.cpp
@@ -37,6 +37,28 @@ SimpleProperties::Writer::add(Uint16 key, Uint32 value){
}
bool
+SimpleProperties::Writer::add(const char * value, int len){
+ const Uint32 valLen = (len + 3) / 4;
+
+ if ((len % 4) == 0)
+ return putWords((Uint32*)value, valLen);
+
+ const Uint32 putLen= valLen - 1;
+ if (!putWords((Uint32*)value, putLen))
+ return false;
+
+ // Special handling of last bytes
+ union {
+ Uint32 lastWord;
+ char lastBytes[4];
+ };
+ memcpy(lastBytes,
+ value + putLen*4,
+ len - putLen*4);
+ return putWord(lastWord);
+}
+
+bool
SimpleProperties::Writer::add(Uint16 key, const char * value){
Uint32 head = StringValue;
head <<= 16;
@@ -46,9 +68,9 @@ SimpleProperties::Writer::add(Uint16 key, const char * value){
Uint32 strLen = strlen(value) + 1; // Including NULL-byte
if(!putWord(htonl(strLen)))
return false;
-
- const Uint32 valLen = (strLen + 3) / 4;
- return putWords((Uint32*)value, valLen);
+
+ return add(value, (int)strLen);
+
}
bool
@@ -60,9 +82,8 @@ SimpleProperties::Writer::add(Uint16 key, const void* value, int len){
return false;
if(!putWord(htonl(len)))
return false;
-
- const Uint32 valLen = (len + 3) / 4;
- return putWords((Uint32*)value, valLen);
+
+ return add((const char*)value, len);
}
SimpleProperties::Reader::Reader(){
@@ -392,6 +413,7 @@ UtilBufferWriter::putWords(const Uint32 * src, Uint32 len){
return (m_buf.append(src, 4 * len) == 0);
}
+
Uint32
UtilBufferWriter::getWordsUsed() const { return m_buf.length() / 4;}
diff --git a/ndb/src/common/util/SocketClient.cpp b/ndb/src/common/util/SocketClient.cpp
index 38df1417eb8..821624eb5c4 100644
--- a/ndb/src/common/util/SocketClient.cpp
+++ b/ndb/src/common/util/SocketClient.cpp
@@ -57,6 +57,8 @@ SocketClient::init()
return false;
}
+ DBUG_PRINT("info",("NDB_SOCKET: %d", m_sockfd));
+
return true;
}
diff --git a/ndb/src/common/util/SocketServer.cpp b/ndb/src/common/util/SocketServer.cpp
index 6019d24d736..15dca2d96b1 100644
--- a/ndb/src/common/util/SocketServer.cpp
+++ b/ndb/src/common/util/SocketServer.cpp
@@ -64,6 +64,8 @@ SocketServer::tryBind(unsigned short port, const char * intface) {
return false;
}
+ DBUG_PRINT("info",("NDB_SOCKET: %d", sock));
+
const int on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(const char*)&on, sizeof(on)) == -1) {
@@ -104,6 +106,8 @@ SocketServer::setup(SocketServer::Service * service,
DBUG_RETURN(false);
}
+ DBUG_PRINT("info",("NDB_SOCKET: %d", sock));
+
const int on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(const char*)&on, sizeof(on)) == -1) {
diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c
index 3157f3bc356..a7e103c3dab 100644
--- a/ndb/src/common/util/version.c
+++ b/ndb/src/common/util/version.c
@@ -38,22 +38,24 @@ Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) {
}
-const char * getVersionString(Uint32 version, const char * status) {
- char buff[100];
+char ndb_version_string_buf[NDB_VERSION_STRING_BUF_SZ];
+const char * getVersionString(Uint32 version, const char * status,
+ char *buf, unsigned sz)
+{
if (status && status[0] != 0)
- basestring_snprintf(buff, sizeof(buff),
+ basestring_snprintf(buf, sz,
"Version %d.%d.%d (%s)",
getMajor(version),
getMinor(version),
getBuild(version),
status);
else
- basestring_snprintf(buff, sizeof(buff),
+ basestring_snprintf(buf, sz,
"Version %d.%d.%d",
getMajor(version),
getMinor(version),
getBuild(version));
- return strdup(buff);
+ return buf;
}
typedef enum {
@@ -90,6 +92,7 @@ void ndbSetOwnVersion() {}
#ifndef TEST_VERSION
struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
+ { MAKE_VERSION(5,0,NDB_VERSION_BUILD), 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(4,1,10), MAKE_VERSION(4,1,9), UG_Exact },
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index 03309f3ac67..2a661104347 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -6458,6 +6458,7 @@ void Dbdih::execDIADDTABREQ(Signal* signal)
ndbrequire(noReplicas == cnoReplicas); // Only allowed
if (ERROR_INSERTED(7173)) {
+ CLEAR_ERROR_INSERT_VALUE;
addtabrefuseLab(signal, connectPtr, ZREPLERROR1);
return;
}
diff --git a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
index bff79215264..e134609df0a 100644
--- a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
+++ b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
@@ -257,8 +257,8 @@ private:
void hbReceivedLab(Signal* signal);
void sendCmRegrefLab(Signal* signal, BlockReference ref,
CmRegRef::ErrorCode);
- void systemErrorBecauseOtherNodeFailed(Signal* signal, NodeId);
- void systemErrorLab(Signal* signal,
+ void systemErrorBecauseOtherNodeFailed(Signal* signal, Uint32 line, NodeId);
+ void systemErrorLab(Signal* signal, Uint32 line,
const char* message = NULL);
void prepFailReqLab(Signal* signal);
void prepFailConfLab(Signal* signal);
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index 04373dae93c..621ec70fbe1 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -76,7 +76,7 @@ void Qmgr::execCM_HEARTBEAT(Signal* signal)
void Qmgr::execCM_NODEINFOREF(Signal* signal)
{
jamEntry();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
return;
}//Qmgr::execCM_NODEINFOREF()
@@ -121,7 +121,7 @@ void Qmgr::execCONTINUEB(Signal* signal)
default:
jam();
// ZCOULD_NOT_OCCUR_ERROR;
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
return;
break;
}//switch
@@ -593,7 +593,7 @@ void Qmgr::execCM_REGCONF(Signal* signal)
jam();
char buf[128];
BaseString::snprintf(buf,sizeof(buf),"incompatible version own=0x%x other=0x%x, shutting down", NDB_VERSION, cmRegConf->presidentVersion);
- systemErrorLab(signal, buf);
+ systemErrorLab(signal, __LINE__, buf);
return;
}
@@ -688,7 +688,7 @@ void Qmgr::execCM_REGREF(Signal* signal)
switch (TrefuseReason) {
case CmRegRef::ZINCOMPATIBLE_VERSION:
jam();
- systemErrorLab(signal, "incompatible version, connection refused by running ndb node");
+ systemErrorLab(signal, __LINE__, "incompatible version, connection refused by running ndb node");
break;
case CmRegRef::ZBUSY:
case CmRegRef::ZBUSY_TO_PRES:
@@ -1751,7 +1751,7 @@ void Qmgr::execAPI_FAILCONF(Signal* signal)
if (failedNodePtr.p->rcv[0] == failedNodePtr.p->rcv[1]) {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
} else {
jam();
failedNodePtr.p->rcv[0] = 0;
@@ -1763,7 +1763,7 @@ void Qmgr::execAPI_FAILCONF(Signal* signal)
ndbout << "failedNodePtr.p->failState = "
<< (Uint32)(failedNodePtr.p->failState) << endl;
#endif
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
}//if
return;
}//Qmgr::execAPI_FAILCONF()
@@ -1780,7 +1780,7 @@ void Qmgr::execNDB_FAILCONF(Signal* signal)
failedNodePtr.p->failState = NORMAL;
} else {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
}//if
if (cpresident == getOwnNodeId()) {
jam();
@@ -1931,20 +1931,13 @@ void Qmgr::execAPI_REGREQ(Signal* signal)
#endif
bool compatability_check;
- switch(getNodeInfo(apiNodePtr.i).getType()){
+ NodeInfo::NodeType type= getNodeInfo(apiNodePtr.i).getType();
+ switch(type){
case NodeInfo::API:
compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version);
- if (!compatability_check)
- infoEvent("Connection attempt from api or mysqld id=%d with %s "
- "incompatible with %s", apiNodePtr.i,
- getVersionString(version,""), NDB_VERSION_STRING);
break;
case NodeInfo::MGM:
compatability_check = ndbCompatible_ndb_mgmt(NDB_VERSION, version);
- if (!compatability_check)
- infoEvent("Connection attempt from management server id=%d with %s "
- "incompatible with %s", apiNodePtr.i,
- getVersionString(version,""), NDB_VERSION_STRING);
break;
case NodeInfo::REP:
// compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version);
@@ -1953,13 +1946,19 @@ void Qmgr::execAPI_REGREQ(Signal* signal)
case NodeInfo::INVALID:
default:
sendApiRegRef(signal, ref, ApiRegRef::WrongType);
- infoEvent("Invalid connection attempt with type %d",
- getNodeInfo(apiNodePtr.i).getType());
+ infoEvent("Invalid connection attempt with type %d", type);
return;
}
if (!compatability_check) {
jam();
+ char buf[NDB_VERSION_STRING_BUF_SZ];
+ infoEvent("Connection attempt from %s id=%d with %s "
+ "incompatible with %s",
+ type == NodeInfo::API ? "api or mysqld" : "management server",
+ apiNodePtr.i,
+ getVersionString(version,"",buf,sizeof(buf)),
+ NDB_VERSION_STRING);
apiNodePtr.p->phase = ZAPI_INACTIVE;
sendApiRegRef(signal, ref, ApiRegRef::UnsupportedVersion);
return;
@@ -2085,7 +2084,7 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode,
ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec);
if (failedNodePtr.i == getOwnNodeId()) {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
return;
}//if
@@ -2093,7 +2092,7 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode,
ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
if (myNodePtr.p->phase != ZRUNNING) {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
return;
}//if
TnoFailedNodes = cnoFailedNodes;
@@ -2172,7 +2171,7 @@ void Qmgr::execPREP_FAILREQ(Signal* signal)
ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
if (myNodePtr.p->phase != ZRUNNING) {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
return;
}//if
@@ -2675,7 +2674,7 @@ void Qmgr::execREAD_NODESREQ(Signal* signal)
ReadNodesConf::SignalLength, JBB);
}//Qmgr::execREAD_NODESREQ()
-void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal,
+void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, Uint32 line,
NodeId failedNodeId) {
jam();
@@ -2687,11 +2686,11 @@ void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal,
"Node was shutdown during startup because node %d failed",
failedNodeId);
- progError(__LINE__, ERR_SR_OTHERNODEFAILED, buf);
+ progError(line, ERR_SR_OTHERNODEFAILED, buf);
}
-void Qmgr::systemErrorLab(Signal* signal, const char * message)
+void Qmgr::systemErrorLab(Signal* signal, Uint32 line, const char * message)
{
jam();
// Broadcast that this node is failing to other nodes
@@ -2699,7 +2698,7 @@ void Qmgr::systemErrorLab(Signal* signal, const char * message)
// If it's known why shutdown occured
// an error message has been passed to this function
- progError(__LINE__, 0, message);
+ progError(line, 0, message);
return;
}//Qmgr::systemErrorLab()
@@ -2867,7 +2866,7 @@ Uint16 Qmgr::translateDynamicIdToNodeId(Signal* signal, UintR TdynamicId)
}//for
if (TtdiNodeId == ZNIL) {
jam();
- systemErrorLab(signal);
+ systemErrorLab(signal, __LINE__);
}//if
return TtdiNodeId;
}//Qmgr::translateDynamicIdToNodeId()
diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp
index e5e00b78bfa..5808e2ed534 100644
--- a/ndb/src/mgmapi/mgmapi.cpp
+++ b/ndb/src/mgmapi/mgmapi.cpp
@@ -265,6 +265,9 @@ static const Properties *
ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
const char *cmd, const Properties *cmd_args)
{
+ DBUG_ENTER("ndb_mgm_call");
+ DBUG_PRINT("enter",("handle->socket: %d, cmd: %s",
+ handle->socket, cmd));
SocketOutputStream out(handle->socket);
SocketInputStream in(handle->socket, handle->read_timeout);
@@ -331,7 +334,8 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
<< "' status=" << (Uint32)ctx.m_status
<< ", curr=" << ctx.m_currentToken
<< endl;
- DBUG_PRINT("info",("parser.parse returned NULL"));
+ DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s",
+ ctx.m_status, ctx.m_currentToken));
}
#ifdef MGMAPI_LOG
else {
@@ -341,7 +345,7 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
p->print(handle->logfile, "IN: ");
}
#endif
- return p;
+ DBUG_RETURN(p);
}
/**
diff --git a/ndb/src/mgmapi/ndb_logevent.cpp b/ndb/src/mgmapi/ndb_logevent.cpp
index 2817abcfdbb..27e7c1f36f5 100644
--- a/ndb/src/mgmapi/ndb_logevent.cpp
+++ b/ndb/src/mgmapi/ndb_logevent.cpp
@@ -369,6 +369,9 @@ int ndb_logevent_get_next(const NdbLogEventHandle h,
Properties p;
char buf[256];
+ struct timeval start_time;
+ gettimeofday(&start_time, 0);
+
/* header */
while (1) {
if (in.gets(buf,sizeof(buf)) == 0)
@@ -383,7 +386,22 @@ int ndb_logevent_get_next(const NdbLogEventHandle h,
}
if ( strcmp("log event reply\n", buf) == 0 )
break;
- ndbout_c("skipped: %s", buf);
+
+ if ( strcmp("<PING>\n", buf) )
+ ndbout_c("skipped: %s", buf);
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+ unsigned elapsed_ms= (now.tv_sec-start_time.tv_sec)*1000 +
+ ((signed int)now.tv_usec-(signed int)start_time.tv_usec)/1000;
+
+ if (elapsed_ms >= timeout_in_milliseconds)
+ {
+ // timed out
+ return 0;
+ }
+
+ new (&in) SocketInputStream(h->socket, timeout_in_milliseconds-elapsed_ms);
}
/* read name-value pairs into properties object */
diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp
index 3b57e6d4860..72f6e7869b2 100644
--- a/ndb/src/mgmclient/CommandInterpreter.cpp
+++ b/ndb/src/mgmclient/CommandInterpreter.cpp
@@ -455,11 +455,13 @@ static int do_event_thread;
static void*
event_thread_run(void* m)
{
+ DBUG_ENTER("event_thread_run");
+
NdbMgmHandle handle= *(NdbMgmHandle*)m;
int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
int fd = ndb_mgm_listen_event(handle, filter);
- if (fd > 0)
+ if (fd != NDB_INVALID_SOCKET)
{
do_event_thread= 1;
char *tmp= 0;
@@ -468,15 +470,20 @@ event_thread_run(void* m)
do {
if (tmp == 0) NdbSleep_MilliSleep(10);
if((tmp = in.gets(buf, 1024)))
- ndbout << tmp;
+ {
+ const char ping_token[]= "<PING>";
+ if (memcmp(ping_token,tmp,sizeof(ping_token)-1))
+ ndbout << tmp;
+ }
} while(do_event_thread);
+ NDB_CLOSE_SOCKET(fd);
}
else
{
do_event_thread= -1;
}
- return NULL;
+ DBUG_RETURN(NULL);
}
bool
@@ -516,9 +523,19 @@ CommandInterpreter::connect()
do_event_thread == 0 ||
do_event_thread == -1)
{
- DBUG_PRINT("warning",("thread not started"));
- printf("Warning, event thread startup failed, degraded printouts as result\n");
+ DBUG_PRINT("info",("Warning, event thread startup failed, "
+ "degraded printouts as result, errno=%d",
+ errno));
+ printf("Warning, event thread startup failed, "
+ "degraded printouts as result, errno=%d\n", errno);
do_event_thread= 0;
+ if (m_event_thread)
+ {
+ void *res;
+ NdbThread_WaitFor(m_event_thread, &res);
+ NdbThread_Destroy(&m_event_thread);
+ }
+ ndb_mgm_disconnect(m_mgmsrv2);
}
}
else
@@ -548,6 +565,7 @@ CommandInterpreter::connect()
bool
CommandInterpreter::disconnect()
{
+ DBUG_ENTER("CommandInterpreter::disconnect");
if (m_event_thread) {
void *res;
do_event_thread= 0;
@@ -564,7 +582,7 @@ CommandInterpreter::disconnect()
}
m_connected= false;
}
- return true;
+ DBUG_RETURN(true);
}
//*****************************************************************************
diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp
index 19c84f6ec8d..ba5d0308f1f 100644
--- a/ndb/src/mgmclient/main.cpp
+++ b/ndb/src/mgmclient/main.cpp
@@ -44,7 +44,9 @@ static Ndb_mgmclient* com;
extern "C"
void
-handler(int sig){
+handler(int sig)
+{
+ DBUG_ENTER("handler");
switch(sig){
case SIGPIPE:
/**
@@ -54,6 +56,7 @@ handler(int sig){
com->disconnect();
break;
}
+ DBUG_VOID_RETURN;
}
NDB_STD_OPTS_VARS;
@@ -163,7 +166,8 @@ int main(int argc, char** argv){
com->execute(opt_execute_str,_try_reconnect, &ret);
}
delete com;
-
+
+ ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
return ret;
}
diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp
index 6b9bf7a0978..51356cb75b1 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -569,10 +569,11 @@ MgmtSrvr::check_start()
bool
MgmtSrvr::start(BaseString &error_string)
{
+ DBUG_ENTER("MgmtSrvr::start");
if (_props == NULL) {
if (!check_start()) {
error_string.append("MgmtSrvr.cpp: check_start() failed.");
- return false;
+ DBUG_RETURN(false);
}
}
theFacade= TransporterFacade::theFacadeInstance
@@ -581,12 +582,12 @@ MgmtSrvr::start(BaseString &error_string)
if(theFacade == 0) {
DEBUG("MgmtSrvr.cpp: theFacade is NULL.");
error_string.append("MgmtSrvr.cpp: theFacade is NULL.");
- return false;
+ DBUG_RETURN(false);
}
if ( theFacade->start_instance
(_ownNodeId, (ndb_mgm_configuration*)_config->m_configValues) < 0) {
DEBUG("MgmtSrvr.cpp: TransporterFacade::start_instance < 0.");
- return false;
+ DBUG_RETURN(false);
}
MGM_REQUIRE(_blockNumber == 1);
@@ -602,7 +603,7 @@ MgmtSrvr::start(BaseString &error_string)
error_string.append("MgmtSrvr.cpp: _blockNumber is -1.");
theFacade->stop_instance();
theFacade = 0;
- return false;
+ DBUG_RETURN(false);
}
TransporterRegistry *reg = theFacade->get_registry();
@@ -624,7 +625,6 @@ MgmtSrvr::start(BaseString &error_string)
DBUG_PRINT("info",("Set result: %d: %s",res,msg.c_str()));
}
-
_ownReference = numberToRef(_blockNumber, _ownNodeId);
startEventLog();
@@ -644,7 +644,7 @@ MgmtSrvr::start(BaseString &error_string)
"MgmtSrvr_Service",
NDB_THREAD_PRIO_LOW);
- return true;
+ DBUG_RETURN(true);
}
@@ -658,6 +658,7 @@ MgmtSrvr::~MgmtSrvr()
if(theFacade != 0){
theFacade->stop_instance();
+ delete theFacade;
theFacade = 0;
}
@@ -2141,6 +2142,24 @@ MgmtSrvr::getNodeType(NodeId nodeId) const
return nodeTypes[nodeId];
}
+const char *MgmtSrvr::get_connect_address(Uint32 node_id)
+{
+ if (m_connect_address[node_id].s_addr == 0 &&
+ theFacade && theFacade->theTransporterRegistry &&
+ theFacade->theClusterMgr &&
+ getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB)
+ {
+ const ClusterMgr::Node &node=
+ theFacade->theClusterMgr->getNodeInfo(node_id);
+ if (node.connected)
+ {
+ m_connect_address[node_id]=
+ theFacade->theTransporterRegistry->get_connect_address(node_id);
+ }
+ }
+ return inet_ntoa(m_connect_address[node_id]);
+}
+
void
MgmtSrvr::get_connected_nodes(NodeBitmask &connected_nodes) const
{
@@ -2604,19 +2623,6 @@ MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted)
}
-/*****************************************************************************
- * Area 51 ???
- *****************************************************************************/
-
-MgmtSrvr::Area51
-MgmtSrvr::getStuff()
-{
- Area51 ret;
- ret.theFacade = theFacade;
- ret.theRegistry = theFacade->theTransporterRegistry;
- return ret;
-}
-
NodeId
MgmtSrvr::getPrimaryNode() const {
#if 0
diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp
index 7e13b41438f..b7983e6b441 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.hpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.hpp
@@ -61,6 +61,7 @@ public:
}
void add_listener(const Event_listener&);
+ void check_listeners();
void update_max_log_level(const LogLevel&);
void update_log_level(const LogLevel&);
@@ -519,7 +520,7 @@ public:
ConfigRetriever *get_config_retriever() { return m_config_retriever; };
- const char *get_connect_address(Uint32 node_id) { return inet_ntoa(m_connect_address[node_id]); }
+ const char *get_connect_address(Uint32 node_id);
void get_connected_nodes(NodeBitmask &connected_nodes) const;
SocketServer *get_socket_server() { return m_socket_server; }
@@ -775,16 +776,6 @@ private:
int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type);
ConfigRetriever *m_config_retriever;
-
-public:
- /**
- * This method does not exist
- */
- struct Area51 {
- class TransporterFacade * theFacade;
- class TransporterRegistry * theRegistry;
- };
- Area51 getStuff();
};
inline
diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp
index 1a5101702a0..270d7f716dd 100644
--- a/ndb/src/mgmsrv/Services.cpp
+++ b/ndb/src/mgmsrv/Services.cpp
@@ -272,15 +272,19 @@ ParserRow<MgmApiSession> commands[] = {
};
MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock)
- : SocketServer::Session(sock), m_mgmsrv(mgm) {
+ : SocketServer::Session(sock), m_mgmsrv(mgm)
+{
+ DBUG_ENTER("MgmApiSession::MgmApiSession");
m_input = new SocketInputStream(sock);
m_output = new SocketOutputStream(sock);
m_parser = new Parser_t(commands, *m_input, true, true, true);
m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv);
+ DBUG_VOID_RETURN;
}
MgmApiSession::~MgmApiSession()
{
+ DBUG_ENTER("MgmApiSession::~MgmApiSession");
if (m_input)
delete m_input;
if (m_output)
@@ -289,10 +293,19 @@ MgmApiSession::~MgmApiSession()
delete m_parser;
if (m_allocated_resources)
delete m_allocated_resources;
+ if(m_socket != NDB_INVALID_SOCKET)
+ {
+ NDB_CLOSE_SOCKET(m_socket);
+ m_socket= NDB_INVALID_SOCKET;
+ }
+ DBUG_VOID_RETURN;
}
void
-MgmApiSession::runSession() {
+MgmApiSession::runSession()
+{
+ DBUG_ENTER("MgmApiSession::runSession");
+
Parser_t::Context ctx;
while(!m_stop) {
m_parser->run(ctx, *this);
@@ -321,7 +334,12 @@ MgmApiSession::runSession() {
}
}
if(m_socket != NDB_INVALID_SOCKET)
+ {
NDB_CLOSE_SOCKET(m_socket);
+ m_socket= NDB_INVALID_SOCKET;
+ }
+
+ DBUG_VOID_RETURN;
}
#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
@@ -1259,7 +1277,7 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId)
LogLevel::EventCategory cat;
Logger::LoggerLevel severity;
EventLoggerBase::EventTextFunction textF;
- int i;
+ int i, n;
DBUG_ENTER("Ndb_mgmd_event_service::log");
DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
@@ -1286,19 +1304,22 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId)
Vector<NDB_SOCKET_TYPE> copy;
m_clients.lock();
- for(i = m_clients.size() - 1; i >= 0; i--){
- if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat)){
- if(m_clients[i].m_socket != NDB_INVALID_SOCKET)
+ for(i = m_clients.size() - 1; i >= 0; i--)
+ {
+ if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat))
+ {
+ NDB_SOCKET_TYPE fd= m_clients[i].m_socket;
+ if(fd != NDB_INVALID_SOCKET)
{
int r;
if (m_clients[i].m_parsable)
- r= println_socket(m_clients[i].m_socket,
+ r= println_socket(fd,
MAX_WRITE_TIMEOUT, str.c_str());
else
- r= println_socket(m_clients[i].m_socket,
+ r= println_socket(fd,
MAX_WRITE_TIMEOUT, m_text);
if (r == -1) {
- copy.push_back(m_clients[i].m_socket);
+ copy.push_back(fd);
m_clients.erase(i, false);
}
}
@@ -1306,16 +1327,15 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId)
}
m_clients.unlock();
- for(i = 0; (unsigned)i < copy.size(); i++){
- NDB_CLOSE_SOCKET(copy[i]);
- }
+ if ((n= (int)copy.size()))
+ {
+ for(i= 0; i < n; i++)
+ NDB_CLOSE_SOCKET(copy[i]);
- if(copy.size()){
LogLevel tmp; tmp.clear();
m_clients.lock();
- for(i = 0; (unsigned)i < m_clients.size(); i++){
+ for(i= m_clients.size() - 1; i >= 0; i--)
tmp.set_max(m_clients[i].m_logLevel);
- }
m_clients.unlock();
update_log_level(tmp);
}
@@ -1343,9 +1363,48 @@ Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp)
}
void
-Ndb_mgmd_event_service::add_listener(const Event_listener& client){
+Ndb_mgmd_event_service::check_listeners()
+{
+ int i, n= 0;
+ DBUG_ENTER("Ndb_mgmd_event_service::check_listeners");
+ m_clients.lock();
+ for(i= m_clients.size() - 1; i >= 0; i--)
+ {
+ int fd= m_clients[i].m_socket;
+ DBUG_PRINT("info",("%d %d",i,fd));
+ char buf[1];
+ buf[0]=0;
+ if (fd != NDB_INVALID_SOCKET &&
+ println_socket(fd,MAX_WRITE_TIMEOUT,"<PING>") == -1)
+ {
+ NDB_CLOSE_SOCKET(fd);
+ m_clients.erase(i, false);
+ n=1;
+ }
+ }
+ if (n)
+ {
+ LogLevel tmp; tmp.clear();
+ for(i= m_clients.size() - 1; i >= 0; i--)
+ tmp.set_max(m_clients[i].m_logLevel);
+ update_log_level(tmp);
+ }
+ m_clients.unlock();
+ DBUG_VOID_RETURN;
+}
+
+void
+Ndb_mgmd_event_service::add_listener(const Event_listener& client)
+{
+ DBUG_ENTER("Ndb_mgmd_event_service::add_listener");
+ DBUG_PRINT("enter",("client.m_socket: %d", client.m_socket));
+
+ check_listeners();
+
m_clients.push_back(client);
update_max_log_level(client.m_logLevel);
+
+ DBUG_VOID_RETURN;
}
void
diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp
index 3335fdc827c..07b369d4ebc 100644
--- a/ndb/src/mgmsrv/main.cpp
+++ b/ndb/src/mgmsrv/main.cpp
@@ -96,16 +96,17 @@ read_and_execute(Ndb_mgmclient* com, const char * prompt, int _try_reconnect)
* @struct MgmGlobals
* @brief Global Variables used in the management server
*****************************************************************************/
+
+/** Command line arguments */
+static int opt_daemon; // NOT bool, bool need not be int
+static int opt_non_interactive;
+static int opt_interactive;
+static const char * opt_config_filename= 0;
+
struct MgmGlobals {
MgmGlobals();
~MgmGlobals();
- /** Command line arguments */
- int daemon; // NOT bool, bool need not be int
- int non_interactive;
- int interactive;
- const char * config_filename;
-
/** Stuff found in environment or in local config */
NodeId localNodeId;
bool use_specific_ip;
@@ -120,7 +121,7 @@ struct MgmGlobals {
};
int g_no_nodeid_checks= 0;
-static MgmGlobals glob;
+static MgmGlobals *glob= 0;
/******************************************************************************
* Function prototypes
@@ -144,14 +145,14 @@ static struct my_option my_long_options[] =
{
NDB_STD_OPTS("ndb_mgmd"),
{ "config-file", 'f', "Specify cluster configuration file",
- (gptr*) &glob.config_filename, (gptr*) &glob.config_filename, 0,
+ (gptr*) &opt_config_filename, (gptr*) &opt_config_filename, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "daemon", 'd', "Run ndb_mgmd in daemon mode (default)",
- (gptr*) &glob.daemon, (gptr*) &glob.daemon, 0,
+ (gptr*) &opt_daemon, (gptr*) &opt_daemon, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
{ "interactive", OPT_INTERACTIVE,
"Run interactive. Not supported but provided for testing purposes",
- (gptr*) &glob.interactive, (gptr*) &glob.interactive, 0,
+ (gptr*) &opt_interactive, (gptr*) &opt_interactive, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "no-nodeid-checks", OPT_NO_NODEID_CHECKS,
"Do not provide any node id checks",
@@ -159,7 +160,7 @@ static struct my_option my_long_options[] =
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "nodaemon", OPT_NO_DAEMON,
"Don't run as daemon, but don't read from stdin",
- (gptr*) &glob.non_interactive, (gptr*) &glob.non_interactive, 0,
+ (gptr*) &opt_non_interactive, (gptr*) &opt_non_interactive, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -182,6 +183,7 @@ static void usage()
int main(int argc, char** argv)
{
NDB_INIT(argv[0]);
+ glob= new MgmGlobals;
/**
* OSE specific. Enable shared ownership of file system resources.
@@ -205,40 +207,40 @@ int main(int argc, char** argv)
ndb_std_get_one_option)))
exit(ho_error);
- if (glob.interactive ||
- glob.non_interactive) {
- glob.daemon= 0;
+ if (opt_interactive ||
+ opt_non_interactive) {
+ opt_daemon= 0;
}
- glob.socketServer = new SocketServer();
+ glob->socketServer = new SocketServer();
MgmApiService * mapi = new MgmApiService();
- glob.mgmObject = new MgmtSrvr(glob.socketServer,
- glob.config_filename,
+ glob->mgmObject = new MgmtSrvr(glob->socketServer,
+ opt_config_filename,
opt_connect_str);
- if (glob.mgmObject->init())
+ if (glob->mgmObject->init())
goto error_end;
my_setwd(NdbConfig_get_path(0), MYF(0));
- glob.localNodeId= glob.mgmObject->getOwnNodeId();
- if (glob.localNodeId == 0) {
+ glob->localNodeId= glob->mgmObject->getOwnNodeId();
+ if (glob->localNodeId == 0) {
goto error_end;
}
- glob.port= glob.mgmObject->getPort();
+ glob->port= glob->mgmObject->getPort();
- if (glob.port == 0)
+ if (glob->port == 0)
goto error_end;
- glob.interface_name = 0;
- glob.use_specific_ip = false;
+ glob->interface_name = 0;
+ glob->use_specific_ip = false;
- if(!glob.use_specific_ip){
+ if(!glob->use_specific_ip){
int count= 5; // no of retries for tryBind
- while(!glob.socketServer->tryBind(glob.port, glob.interface_name)){
+ while(!glob->socketServer->tryBind(glob->port, glob->interface_name)){
if (--count > 0) {
NdbSleep_MilliSleep(1000);
continue;
@@ -247,19 +249,20 @@ int main(int argc, char** argv)
"Please check if the port is already used,\n"
"(perhaps a ndb_mgmd is already running),\n"
"and if you are executing on the correct computer",
- (glob.interface_name ? glob.interface_name : "*"), glob.port);
+ (glob->interface_name ? glob->interface_name : "*"), glob->port);
goto error_end;
}
- free(glob.interface_name);
- glob.interface_name = 0;
+ free(glob->interface_name);
+ glob->interface_name = 0;
}
- if(!glob.socketServer->setup(mapi, &glob.port, glob.interface_name)){
+ if(!glob->socketServer->setup(mapi, &glob->port, glob->interface_name))
+ {
ndbout_c("Unable to setup management port: %d!\n"
"Please check if the port is already used,\n"
"(perhaps a ndb_mgmd is already running),\n"
"and if you are executing on the correct computer",
- glob.port);
+ glob->port);
delete mapi;
goto error_end;
}
@@ -267,12 +270,12 @@ int main(int argc, char** argv)
/* Construct a fake connectstring to connect back to ourselves */
char connect_str[20];
if(!opt_connect_str) {
- snprintf(connect_str,20,"localhost:%u",glob.mgmObject->getPort());
+ snprintf(connect_str,20,"localhost:%u",glob->mgmObject->getPort());
opt_connect_str= connect_str;
}
- glob.mgmObject->set_connect_string(opt_connect_str);
+ glob->mgmObject->set_connect_string(opt_connect_str);
- if(!glob.mgmObject->check_start()){
+ if(!glob->mgmObject->check_start()){
ndbout_c("Unable to check start management server.");
ndbout_c("Probably caused by illegal initial configuration file.");
goto error_end;
@@ -283,7 +286,7 @@ int main(int argc, char** argv)
* config info
*/
int mgm_connect_result;
- mgm_connect_result = glob.mgmObject->get_config_retriever()->
+ mgm_connect_result = glob->mgmObject->get_config_retriever()->
do_connect(0,0,0);
if(mgm_connect_result<0) {
@@ -292,11 +295,10 @@ int main(int argc, char** argv)
ndbout_c("This is probably a bug.");
}
-
- if (glob.daemon) {
+ if (opt_daemon) {
// Become a daemon
- char *lockfile= NdbConfig_PidFileName(glob.localNodeId);
- char *logfile= NdbConfig_StdoutFileName(glob.localNodeId);
+ char *lockfile= NdbConfig_PidFileName(glob->localNodeId);
+ char *logfile= NdbConfig_StdoutFileName(glob->localNodeId);
NdbAutoPtr<char> tmp_aptr1(lockfile), tmp_aptr2(logfile);
if (NdbDaemon_Make(lockfile, logfile, 0) == -1) {
@@ -310,7 +312,7 @@ int main(int argc, char** argv)
#endif
{
BaseString error_string;
- if(!glob.mgmObject->start(error_string)){
+ if(!glob->mgmObject->start(error_string)){
ndbout_c("Unable to start management server.");
ndbout_c("Probably caused by illegal initial configuration file.");
ndbout_c(error_string.c_str());
@@ -318,8 +320,8 @@ int main(int argc, char** argv)
}
}
- //glob.mgmObject->saveConfig();
- mapi->setMgm(glob.mgmObject);
+ //glob->mgmObject->saveConfig();
+ mapi->setMgm(glob->mgmObject);
char msg[256];
BaseString::snprintf(msg, sizeof(msg),
@@ -328,20 +330,20 @@ int main(int argc, char** argv)
g_eventLogger.info(msg);
BaseString::snprintf(msg, 256, "Id: %d, Command port: %d",
- glob.localNodeId, glob.port);
+ glob->localNodeId, glob->port);
ndbout_c(msg);
g_eventLogger.info(msg);
g_StopServer = false;
- glob.socketServer->startServer();
+ glob->socketServer->startServer();
#if ! defined NDB_OSE && ! defined NDB_SOFTOSE
- if(glob.interactive) {
+ if(opt_interactive) {
BaseString con_str;
- if(glob.interface_name)
- con_str.appfmt("host=%s:%d", glob.interface_name, glob.port);
+ if(glob->interface_name)
+ con_str.appfmt("host=%s:%d", glob->interface_name, glob->port);
else
- con_str.appfmt("localhost:%d", glob.port);
+ con_str.appfmt("localhost:%d", glob->port);
Ndb_mgmclient com(con_str.c_str(), 1);
while(g_StopServer != true && read_and_execute(&com, "ndb_mgm> ", 1));
} else
@@ -352,22 +354,23 @@ int main(int argc, char** argv)
}
g_eventLogger.info("Shutting down server...");
- glob.socketServer->stopServer();
- glob.socketServer->stopSessions();
+ glob->socketServer->stopServer();
+ glob->mgmObject->get_config_retriever()->disconnect();
+ glob->socketServer->stopSessions(true);
g_eventLogger.info("Shutdown complete");
+ delete glob;
+ ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
return 0;
error_end:
+ delete glob;
+ ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
return 1;
}
MgmGlobals::MgmGlobals(){
// Default values
port = 0;
- config_filename = NULL;
interface_name = 0;
- daemon = 1;
- non_interactive = 0;
- interactive = 0;
socketServer = 0;
mgmObject = 0;
}
diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp
index 42b3b01bca1..ef9367ef10e 100644
--- a/ndb/src/ndbapi/ClusterMgr.cpp
+++ b/ndb/src/ndbapi/ClusterMgr.cpp
@@ -64,16 +64,21 @@ ClusterMgr::ClusterMgr(TransporterFacade & _facade):
theStop(0),
theFacade(_facade)
{
+ DBUG_ENTER("ClusterMgr::ClusterMgr");
ndbSetOwnVersion();
clusterMgrThreadMutex = NdbMutex_Create();
noOfAliveNodes= 0;
noOfConnectedNodes= 0;
theClusterMgrThread= 0;
+ DBUG_VOID_RETURN;
}
-ClusterMgr::~ClusterMgr(){
+ClusterMgr::~ClusterMgr()
+{
+ DBUG_ENTER("ClusterMgr::~ClusterMgr");
doStop();
NdbMutex_Destroy(clusterMgrThreadMutex);
+ DBUG_VOID_RETURN;
}
void
@@ -152,7 +157,6 @@ ClusterMgr::doStop( ){
if (theClusterMgrThread) {
NdbThread_WaitFor(theClusterMgrThread, &status);
NdbThread_Destroy(&theClusterMgrThread);
- theClusterMgrThread= 0;
}
NdbMutex_Unlock(clusterMgrThreadMutex);
DBUG_VOID_RETURN;
@@ -481,6 +485,8 @@ ClusterMgr::reportNodeFailed(NodeId nodeId){
ArbitMgr::ArbitMgr(TransporterFacade & _fac)
: theFacade(_fac)
{
+ DBUG_ENTER("ArbitMgr::ArbitMgr");
+
theThreadMutex = NdbMutex_Create();
theInputCond = NdbCondition_Create();
theInputMutex = NdbMutex_Create();
@@ -498,13 +504,17 @@ ArbitMgr::ArbitMgr(TransporterFacade & _fac)
memset(&theChooseReq1, 0, sizeof(theChooseReq1));
memset(&theChooseReq2, 0, sizeof(theChooseReq2));
memset(&theStopOrd, 0, sizeof(theStopOrd));
+
+ DBUG_VOID_RETURN;
}
ArbitMgr::~ArbitMgr()
{
+ DBUG_ENTER("ArbitMgr::~ArbitMgr");
NdbMutex_Destroy(theThreadMutex);
NdbCondition_Destroy(theInputCond);
NdbMutex_Destroy(theInputMutex);
+ DBUG_VOID_RETURN;
}
// Start arbitrator thread. This is kernel request.
@@ -521,7 +531,7 @@ ArbitMgr::doStart(const Uint32* theData)
sendSignalToThread(aSignal);
void* value;
NdbThread_WaitFor(theThread, &value);
- theThread = NULL;
+ NdbThread_Destroy(&theThread);
theState = StateInit;
theInputFull = false;
}
@@ -560,7 +570,7 @@ ArbitMgr::doStop(const Uint32* theData)
sendSignalToThread(aSignal);
void* value;
NdbThread_WaitFor(theThread, &value);
- theThread = NULL;
+ NdbThread_Destroy(&theThread);
theState = StateInit;
}
NdbMutex_Unlock(theThreadMutex);
diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp
index ccc45a04824..3d14df908a0 100644
--- a/ndb/src/ndbapi/DictCache.cpp
+++ b/ndb/src/ndbapi/DictCache.cpp
@@ -80,11 +80,14 @@ LocalDictCache::drop(const char * name){
* Global cache
*/
GlobalDictCache::GlobalDictCache(){
+ DBUG_ENTER("GlobalDictCache::GlobalDictCache");
m_tableHash.createHashTable();
m_waitForTableCondition = NdbCondition_Create();
+ DBUG_VOID_RETURN;
}
GlobalDictCache::~GlobalDictCache(){
+ DBUG_ENTER("GlobalDictCache::~GlobalDictCache");
NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
while(curr != 0){
Vector<TableVersion> * vers = curr->theData;
@@ -94,20 +97,52 @@ GlobalDictCache::~GlobalDictCache(){
delete (* vers)[i].m_impl;
}
delete curr->theData;
+ curr->theData= NULL;
curr = m_tableHash.getNext(curr);
}
-
m_tableHash.releaseHashTable();
NdbCondition_Destroy(m_waitForTableCondition);
+ DBUG_VOID_RETURN;
}
-#include <NdbOut.hpp>
+void GlobalDictCache::printCache()
+{
+ DBUG_ENTER("GlobalDictCache::printCache");
+ NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
+ while(curr != 0){
+ DBUG_PRINT("curr", ("len: %d, hash: %d, lk: %d, str: %s",
+ curr->len, curr->hash, curr->localkey1, curr->str));
+ if (curr->theData){
+ Vector<TableVersion> * vers = curr->theData;
+ const unsigned sz = vers->size();
+ for(unsigned i = 0; i<sz ; i++){
+ TableVersion tv= (*vers)[i];
+ DBUG_PRINT(" ", ("vers[%d]: ver: %d, refCount: %d, status: %d",
+ sz, tv.m_version, tv.m_refCount, tv.m_status));
+ if(tv.m_impl != 0)
+ {
+ DBUG_PRINT(" ", ("m_impl: internalname: %s",
+ tv.m_impl->m_internalName.c_str()));
+ }
+ }
+ }
+ else
+ {
+ DBUG_PRINT(" ", ("NULL"));
+ }
+ curr = m_tableHash.getNext(curr);
+ }
+ DBUG_VOID_RETURN;
+}
-NdbTableImpl *
+NdbTableImpl *
GlobalDictCache::get(const char * name)
{
+ DBUG_ENTER("GlobalDictCache::get");
+ DBUG_PRINT("enter", ("name: %s", name));
+
const Uint32 len = strlen(name);
- Vector<TableVersion> * versions = 0;
+ Vector<TableVersion> * versions = 0;
versions = m_tableHash.getData(name, len);
if(versions == 0){
versions = new Vector<TableVersion>(2);
@@ -122,7 +157,7 @@ GlobalDictCache::get(const char * name)
switch(ver->m_status){
case OK:
ver->m_refCount++;
- return ver->m_impl;
+ DBUG_RETURN(ver->m_impl);
case DROPPED:
retreive = true; // Break loop
break;
@@ -141,24 +176,28 @@ GlobalDictCache::get(const char * name)
tmp.m_status = RETREIVING;
tmp.m_refCount = 1; // The one retreiving it
versions->push_back(tmp);
- return 0;
+ DBUG_RETURN(0);
}
NdbTableImpl *
GlobalDictCache::put(const char * name, NdbTableImpl * tab)
{
+ DBUG_ENTER("GlobalDictCache::put");
+ DBUG_PRINT("enter", ("name: %s, internal_name: %s",
+ name, tab ? tab->m_internalName.c_str() : "tab NULL"));
+
const Uint32 len = strlen(name);
Vector<TableVersion> * vers = m_tableHash.getData(name, len);
if(vers == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
const Uint32 sz = vers->size();
if(sz == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
@@ -171,7 +210,7 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab)
}
if(tab == 0){
- // No table found in db
+ DBUG_PRINT("info", ("No table found in db"));
vers->erase(sz - 1);
} else {
ver.m_impl = tab;
@@ -180,74 +219,84 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab)
}
NdbCondition_Broadcast(m_waitForTableCondition);
- return tab;
+ DBUG_RETURN(tab);
}
void
GlobalDictCache::drop(NdbTableImpl * tab)
{
+ DBUG_ENTER("GlobalDictCache::drop");
+ DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str()));
+
unsigned i;
const Uint32 len = strlen(tab->m_internalName.c_str());
Vector<TableVersion> * vers =
m_tableHash.getData(tab->m_internalName.c_str(), len);
if(vers == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
const Uint32 sz = vers->size();
if(sz == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
-
+
for(i = 0; i < sz; i++){
TableVersion & ver = (* vers)[i];
if(ver.m_impl == tab){
- if(ver.m_refCount == 0 || ver.m_status == RETREIVING ||
+ if(ver.m_refCount == 0 || ver.m_status == RETREIVING ||
ver.m_version != tab->m_version){
- ndbout_c("Dropping with refCount=%d status=%d impl=%p",
- ver.m_refCount, ver.m_status, ver.m_impl);
+ DBUG_PRINT("info", ("Dropping with refCount=%d status=%d impl=%p",
+ ver.m_refCount, ver.m_status, ver.m_impl));
break;
}
-
+ DBUG_PRINT("info", ("Found table to drop, i: %d, name: %s",
+ i, ver.m_impl->m_internalName.c_str()));
ver.m_refCount--;
ver.m_status = DROPPED;
if(ver.m_refCount == 0){
+ DBUG_PRINT("info", ("refCount is zero, deleting m_impl"))
delete ver.m_impl;
vers->erase(i);
}
- return;
+ DBUG_VOID_RETURN;
}
}
-
+
for(i = 0; i<sz; i++){
TableVersion & ver = (* vers)[i];
- ndbout_c("%d: version: %d refCount: %d status: %d impl: %p",
- i, ver.m_version, ver.m_refCount, ver.m_status, ver.m_impl);
+ DBUG_PRINT("info", ("%d: version: %d refCount: %d status: %d impl: %p",
+ i, ver.m_version, ver.m_refCount,
+ ver.m_status, ver.m_impl));
}
abort();
}
void
-GlobalDictCache::release(NdbTableImpl * tab){
+GlobalDictCache::release(NdbTableImpl * tab)
+{
+ DBUG_ENTER("GlobalDictCache::release");
+ DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str()));
+
unsigned i;
const Uint32 len = strlen(tab->m_internalName.c_str());
Vector<TableVersion> * vers =
m_tableHash.getData(tab->m_internalName.c_str(), len);
if(vers == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
const Uint32 sz = vers->size();
if(sz == 0){
// Should always tried to retreive it first
- // and then there should be a record
+ // and thus there should be a record
abort();
}
@@ -256,20 +305,21 @@ GlobalDictCache::release(NdbTableImpl * tab){
if(ver.m_impl == tab){
if(ver.m_refCount == 0 || ver.m_status == RETREIVING ||
ver.m_version != tab->m_version){
- ndbout_c("Releasing with refCount=%d status=%d impl=%p",
- ver.m_refCount, ver.m_status, ver.m_impl);
+ DBUG_PRINT("info", ("Releasing with refCount=%d status=%d impl=%p",
+ ver.m_refCount, ver.m_status, ver.m_impl));
break;
}
ver.m_refCount--;
- return;
+ DBUG_VOID_RETURN;
}
}
for(i = 0; i<sz; i++){
TableVersion & ver = (* vers)[i];
- ndbout_c("%d: version: %d refCount: %d status: %d impl: %p",
- i, ver.m_version, ver.m_refCount, ver.m_status, ver.m_impl);
+ DBUG_PRINT("info", ("%d: version: %d refCount: %d status: %d impl: %p",
+ i, ver.m_version, ver.m_refCount,
+ ver.m_status, ver.m_impl));
}
abort();
diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp
index ca31c345396..d9bf810a685 100644
--- a/ndb/src/ndbapi/DictCache.hpp
+++ b/ndb/src/ndbapi/DictCache.hpp
@@ -76,6 +76,8 @@ public:
};
private:
+ void printCache();
+
struct TableVersion {
Uint32 m_version;
Uint32 m_refCount;
diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp
index c48e70f1d51..7893aaae15c 100644
--- a/ndb/src/ndbapi/Ndb.cpp
+++ b/ndb/src/ndbapi/Ndb.cpp
@@ -425,12 +425,20 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
DBUG_ENTER("Ndb::startTransactionLocal");
DBUG_PRINT("enter", ("nodeid: %d", nodeId));
+ if(unlikely(theRemainingStartTransactions == 0))
+ {
+ theError.code = 4006;
+ DBUG_RETURN(0);
+ }
+
NdbTransaction* tConnection;
Uint64 tFirstTransId = theFirstTransId;
tConnection = doConnect(nodeId);
if (tConnection == NULL) {
DBUG_RETURN(NULL);
}//if
+
+ theRemainingStartTransactions--;
NdbTransaction* tConNext = theTransactionList;
tConnection->init();
theTransactionList = tConnection; // into a transaction list.
@@ -481,6 +489,7 @@ Ndb::closeTransaction(NdbTransaction* aConnection)
CHECK_STATUS_MACRO_VOID;
tCon = theTransactionList;
+ theRemainingStartTransactions++;
DBUG_PRINT("info",("close trans: 0x%x transid: 0x%llx",
aConnection, aConnection->getTransactionId()));
@@ -751,16 +760,14 @@ Remark: Returns a new TupleId to the application.
The TupleId comes from SYSTAB_0 where SYSKEY_0 = TableId.
It is initialized to (TableId << 48) + 1 in NdbcntrMain.cpp.
****************************************************************************/
-#define DEBUG_TRACE(msg) \
-// ndbout << __FILE__ << " line: " << __LINE__ << " msg: " << msg << endl
-
Uint64
Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize)
{
DBUG_ENTER("getAutoIncrementValue");
- const char * internalTableName = internalizeTableName(aTableName);
+ BaseString internal_tabname(internalize_table_name(aTableName));
+
Ndb_local_table_info *info=
- theDictionary->get_local_table_info(internalTableName, false);
+ theDictionary->get_local_table_info(internal_tabname, false);
if (info == 0)
DBUG_RETURN(~(Uint64)0);
const NdbTableImpl *table= info->m_table_impl;
@@ -812,7 +819,7 @@ Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize)
Uint64
Ndb::readAutoIncrementValue(const char* aTableName)
{
- DBUG_ENTER("readtAutoIncrementValue");
+ DBUG_ENTER("readAutoIncrementValue");
const NdbTableImpl* table = theDictionary->getTable(aTableName);
if (table == 0) {
theError= theDictionary->getNdbError();
@@ -826,7 +833,7 @@ Ndb::readAutoIncrementValue(const char* aTableName)
Uint64
Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable)
{
- DBUG_ENTER("readtAutoIncrementValue");
+ DBUG_ENTER("readAutoIncrementValue");
if (aTable == 0)
DBUG_RETURN(~(Uint64)0);
const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
@@ -848,62 +855,63 @@ Ndb::readTupleIdFromNdb(Uint32 aTableId)
bool
Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase)
{
- DEBUG_TRACE("setAutoIncrementValue " << val);
- const char * internalTableName= internalizeTableName(aTableName);
+ DBUG_ENTER("setAutoIncrementValue");
+ BaseString internal_tabname(internalize_table_name(aTableName));
+
Ndb_local_table_info *info=
- theDictionary->get_local_table_info(internalTableName, false);
+ theDictionary->get_local_table_info(internal_tabname, false);
if (info == 0) {
theError= theDictionary->getNdbError();
- return false;
+ DBUG_RETURN(false);
}
const NdbTableImpl* table= info->m_table_impl;
- return setTupleIdInNdb(table->m_tableId, val, increase);
+ DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase));
}
bool
Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase)
{
- DEBUG_TRACE("setAutoIncrementValue " << val);
+ DBUG_ENTER("setAutoIncrementValue");
if (aTable == 0)
- return ~(Uint64)0;
+ DBUG_RETURN(~(Uint64)0);
const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
- return setTupleIdInNdb(table->m_tableId, val, increase);
+ DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase));
}
-bool
+bool
Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase )
{
- DEBUG_TRACE("setTupleIdInNdb");
+ DBUG_ENTER("setTupleIdInNdb(const char*, ...)");
const NdbTableImpl* table = theDictionary->getTable(aTableName);
if (table == 0) {
theError= theDictionary->getNdbError();
- return false;
+ DBUG_RETURN(false);
}
- return setTupleIdInNdb(table->m_tableId, val, increase);
+ DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase));
}
bool
Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase )
{
- DEBUG_TRACE("setTupleIdInNdb");
+ DBUG_ENTER("setTupleIdInNdb(Uint32, ...)");
if (increase)
{
if (theFirstTupleId[aTableId] != theLastTupleId[aTableId])
{
// We have a cache sequence
if (val <= theFirstTupleId[aTableId]+1)
- return false;
+ DBUG_RETURN(false);
if (val <= theLastTupleId[aTableId])
{
theFirstTupleId[aTableId] = val - 1;
- return true;
+ DBUG_RETURN(true);
}
// else continue;
- }
- return (opTupleIdOnNdb(aTableId, val, 2) == val);
+ }
+ DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 2) == val));
}
else
- return (opTupleIdOnNdb(aTableId, val, 1) == val);
+ DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 1) == val));
}
Uint64
@@ -1143,25 +1151,63 @@ Ndb::externalizeIndexName(const char * internalIndexName)
return externalizeIndexName(internalIndexName, usingFullyQualifiedNames());
}
-const char *
-Ndb::internalizeTableName(const char * externalTableName)
+
+const BaseString
+Ndb::internalize_table_name(const char *external_name) const
{
+ BaseString ret;
+ DBUG_ENTER("internalize_table_name");
+ DBUG_PRINT("enter", ("external_name: %s", external_name));
+
if (fullyQualifiedNames)
- return theImpl->internalize_table_name(externalTableName);
+ {
+ /* Internal table name format <db>/<schema>/<table>
+ <db>/<schema> is already available in m_prefix
+ so just concat the two strings
+ */
+ ret.assfmt("%s%s",
+ theImpl->m_prefix.c_str(),
+ external_name);
+ }
else
- return externalTableName;
+ ret.assign(external_name);
+
+ DBUG_PRINT("exit", ("internal_name: %s", ret.c_str()));
+ DBUG_RETURN(ret);
}
-
-const char *
-Ndb::internalizeIndexName(const NdbTableImpl * table,
- const char * externalIndexName)
+
+
+const BaseString
+Ndb::internalize_index_name(const NdbTableImpl * table,
+ const char * external_name) const
{
+ BaseString ret;
+ DBUG_ENTER("internalize_index_name");
+ DBUG_PRINT("enter", ("external_name: %s, table_id: %d",
+ external_name, table ? table->m_tableId : ~0));
+ if (!table)
+ {
+ DBUG_PRINT("error", ("!table"));
+ return ret;
+ }
+
if (fullyQualifiedNames)
- return theImpl->internalize_index_name(table, externalIndexName);
+ {
+ /* Internal index name format <db>/<schema>/<tabid>/<table> */
+ ret.assfmt("%s%d%c%s",
+ theImpl->m_prefix.c_str(),
+ table->m_tableId,
+ table_name_separator,
+ external_name);
+ }
else
- return externalIndexName;
+ ret.assign(external_name);
+
+ DBUG_PRINT("exit", ("internal_name: %s", ret.c_str()));
+ DBUG_RETURN(ret);
}
+
const BaseString
Ndb::getDatabaseFromInternalName(const char * internalName)
{
diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp
index 0638f6e4c51..d06d6b4ef4d 100644
--- a/ndb/src/ndbapi/NdbBlob.cpp
+++ b/ndb/src/ndbapi/NdbBlob.cpp
@@ -24,34 +24,6 @@
#include "NdbBlobImpl.hpp"
#include <NdbScanOperation.hpp>
-#ifdef NDB_BLOB_DEBUG
-#define DBG(x) \
- do { \
- static const char* p = getenv("NDB_BLOB_DEBUG"); \
- if (p == 0 || *p == 0 || *p == '0') break; \
- static char* prefix = "BLOB"; \
- const char* cname = theColumn == NULL ? "-" : theColumn->m_name.c_str(); \
- ndbout << prefix << " " << hex << (void*)this << " " << cname; \
- ndbout << " " << dec << __LINE__ << " " << x << " " << *this << endl; \
- } while (0)
-
-static char*
-ndb_blob_debug(const Uint32* data, unsigned size)
-{
- static char buf[200]; // MT irrelevant
- buf[0] = 0;
- for (unsigned i = 0; i < size; i++) {
- unsigned n = strlen(buf);
- if (n + 10 < sizeof(buf))
- sprintf(buf + n, "%*s%08x", i != 0, "", data[i]);
- }
- return buf;
-}
-
-#else
-#define DBG(x)
-#endif
-
/*
* Reading index table directly (as a table) is faster but there are
* bugs or limitations. Keep the code and make possible to choose.
@@ -63,8 +35,10 @@ static const bool g_ndb_blob_ok_to_read_index_table = false;
inline void
NdbBlob::setState(State newState)
{
- DBG("setState " << newState);
+ DBUG_ENTER("NdbBlob::setState");
+ DBUG_PRINT("info", ("this=%p newState=%u", this, newState));
theState = newState;
+ DBUG_VOID_RETURN;
}
// define blob table
@@ -319,9 +293,9 @@ NdbBlob::getDistKey(Uint32 part)
int
NdbBlob::getTableKeyValue(NdbOperation* anOp)
{
+ DBUG_ENTER("NdbBlob::getTableKeyValue");
Uint32* data = (Uint32*)theKeyBuf.data;
unsigned pos = 0;
- DBG("getTableKeyValue");
for (unsigned i = 0; i < theTable->m_columns.size(); i++) {
NdbColumnImpl* c = theTable->m_columns[i];
assert(c != NULL);
@@ -329,7 +303,7 @@ NdbBlob::getTableKeyValue(NdbOperation* anOp)
unsigned len = c->m_attrSize * c->m_arraySize;
if (anOp->getValue_impl(c, (char*)&data[pos]) == NULL) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
// odd bytes receive no data and must be zeroed
while (len % 4 != 0) {
@@ -340,14 +314,15 @@ NdbBlob::getTableKeyValue(NdbOperation* anOp)
}
}
assert(pos == theKeyBuf.size / 4);
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setTableKeyValue(NdbOperation* anOp)
{
+ DBUG_ENTER("NdbBlob::setTableKeyValue");
+ DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords);
const Uint32* data = (const Uint32*)theKeyBuf.data;
- DBG("setTableKeyValue key=" << ndb_blob_debug(data, theTable->m_keyLenInWords));
const unsigned columns = theTable->m_columns.size();
unsigned pos = 0;
for (unsigned i = 0; i < columns; i++) {
@@ -357,20 +332,21 @@ NdbBlob::setTableKeyValue(NdbOperation* anOp)
unsigned len = c->m_attrSize * c->m_arraySize;
if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
pos += (len + 3) / 4;
}
}
assert(pos == theKeyBuf.size / 4);
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setAccessKeyValue(NdbOperation* anOp)
{
+ DBUG_ENTER("NdbBlob::setAccessKeyValue");
+ DBUG_DUMP("info", theAccessKeyBuf.data, 4 * theAccessTable->m_keyLenInWords);
const Uint32* data = (const Uint32*)theAccessKeyBuf.data;
- DBG("setAccessKeyValue key=" << ndb_blob_debug(data, theAccessTable->m_keyLenInWords));
const unsigned columns = theAccessTable->m_columns.size();
unsigned pos = 0;
for (unsigned i = 0; i < columns; i++) {
@@ -380,57 +356,60 @@ NdbBlob::setAccessKeyValue(NdbOperation* anOp)
unsigned len = c->m_attrSize * c->m_arraySize;
if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
pos += (len + 3) / 4;
}
}
assert(pos == theAccessKeyBuf.size / 4);
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part)
{
+ DBUG_ENTER("NdbBlob::setPartKeyValue");
+ DBUG_PRINT("info", ("dist=%u part=%u key=", getDistKey(part), part));
+ DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords);
Uint32* data = (Uint32*)theKeyBuf.data;
unsigned size = theTable->m_keyLenInWords;
- DBG("setPartKeyValue dist=" << getDistKey(part) << " part=" << part << " key=" << ndb_blob_debug(data, size));
// TODO use attr ids after compatibility with 4.1.7 not needed
if (anOp->equal("PK", theKeyBuf.data) == -1 ||
anOp->equal("DIST", getDistKey(part)) == -1 ||
anOp->equal("PART", part) == -1) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::getHeadInlineValue(NdbOperation* anOp)
{
- DBG("getHeadInlineValue");
+ DBUG_ENTER("NdbBlob::getHeadInlineValue");
theHeadInlineRecAttr = anOp->getValue_impl(theColumn, theHeadInlineBuf.data);
if (theHeadInlineRecAttr == NULL) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
- return 0;
+ DBUG_RETURN(0);
}
void
NdbBlob::getHeadFromRecAttr()
{
+ DBUG_ENTER("NdbBlob::getHeadFromRecAttr");
assert(theHeadInlineRecAttr != NULL);
theNullFlag = theHeadInlineRecAttr->isNULL();
assert(theNullFlag != -1);
theLength = ! theNullFlag ? theHead->length : 0;
- DBG("getHeadFromRecAttr [out]");
+ DBUG_VOID_RETURN;
}
int
NdbBlob::setHeadInlineValue(NdbOperation* anOp)
{
- DBG("setHeadInlineValue");
+ DBUG_ENTER("NdbBlob::setHeadInlineValue");
theHead->length = theLength;
if (theLength < theInlineSize)
memset(theInlineData + theLength, 0, theInlineSize - theLength);
@@ -438,10 +417,10 @@ NdbBlob::setHeadInlineValue(NdbOperation* anOp)
const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data;
if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) {
setErrorCode(anOp);
- return -1;
+ DBUG_RETURN(-1);
}
theHeadInlineUpdateFlag = false;
- return 0;
+ DBUG_RETURN(0);
}
// getValue/setValue
@@ -449,40 +428,42 @@ NdbBlob::setHeadInlineValue(NdbOperation* anOp)
int
NdbBlob::getValue(void* data, Uint32 bytes)
{
- DBG("getValue data=" << hex << data << " bytes=" << dec << bytes);
+ DBUG_ENTER("NdbBlob::getValue");
+ DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes));
if (theGetFlag || theState != Prepared) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
if (! isReadOp() && ! isScanOp()) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
if (data == NULL && bytes != 0) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
theGetFlag = true;
theGetBuf = static_cast<char*>(data);
theGetSetBytes = bytes;
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setValue(const void* data, Uint32 bytes)
{
- DBG("setValue data=" << hex << data << " bytes=" << dec << bytes);
+ DBUG_ENTER("NdbBlob::setValue");
+ DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes));
if (theSetFlag || theState != Prepared) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
if (data == NULL && bytes != 0) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
theSetFlag = true;
theSetBuf = static_cast<const char*>(data);
@@ -495,15 +476,15 @@ NdbBlob::setValue(const void* data, Uint32 bytes)
n = theInlineSize;
assert(thePos == 0);
if (writeDataPrivate(theSetBuf, n) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
theNullFlag = true;
theLength = 0;
}
if (setHeadInlineValue(theNdbOp) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
- return 0;
+ DBUG_RETURN(0);
}
// activation hook
@@ -511,14 +492,15 @@ NdbBlob::setValue(const void* data, Uint32 bytes)
int
NdbBlob::setActiveHook(ActiveHook activeHook, void* arg)
{
- DBG("setActiveHook hook=" << hex << (void*)activeHook << " arg=" << hex << arg);
+ DBUG_ENTER("NdbBlob::setActiveHook");
+ DBUG_PRINT("info", ("hook=%p arg=%p", (void*)activeHook, arg));
if (theState != Prepared) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
theActiveHook = activeHook;
theActiveHookArg = arg;
- return 0;
+ DBUG_RETURN(0);
}
// misc operations
@@ -526,63 +508,64 @@ NdbBlob::setActiveHook(ActiveHook activeHook, void* arg)
int
NdbBlob::getNull(bool& isNull)
{
- DBG("getNull");
+ DBUG_ENTER("NdbBlob::getNull");
if (theState == Prepared && theSetFlag) {
isNull = (theSetBuf == NULL);
- return 0;
+ DBUG_RETURN(0);
}
if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
isNull = theNullFlag;
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setNull()
{
- DBG("setNull");
+ DBUG_ENTER("NdbBlob::setNull");
if (theNullFlag == -1) {
if (theState == Prepared) {
- return setValue(0, 0);
+ DBUG_RETURN(setValue(0, 0));
}
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
if (theNullFlag)
- return 0;
+ DBUG_RETURN(0);
if (deleteParts(0, getPartCount()) == -1)
- return -1;
+ DBUG_RETURN(-1);
theNullFlag = true;
theLength = 0;
theHeadInlineUpdateFlag = true;
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::getLength(Uint64& len)
{
- DBG("getLength");
+ DBUG_ENTER("NdbBlob::getLength");
if (theState == Prepared && theSetFlag) {
len = theGetSetBytes;
- return 0;
+ DBUG_RETURN(0);
}
if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
len = theLength;
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::truncate(Uint64 length)
{
- DBG("truncate [in] length=" << length);
+ DBUG_ENTER("NdbBlob::truncate");
+ DBUG_PRINT("info", ("length=%llu", length));
if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
if (theLength > length) {
if (length > theInlineSize) {
@@ -590,46 +573,46 @@ NdbBlob::truncate(Uint64 length)
Uint32 part2 = getPartNumber(theLength - 1);
assert(part2 >= part1);
if (part2 > part1 && deleteParts(part1 + 1, part2 - part1) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
if (deleteParts(0, getPartCount()) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
theLength = length;
theHeadInlineUpdateFlag = true;
if (thePos > length)
thePos = length;
}
- DBG("truncate [out]");
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::getPos(Uint64& pos)
{
- DBG("getPos");
+ DBUG_ENTER("NdbBlob::getPos");
if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
pos = thePos;
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::setPos(Uint64 pos)
{
- DBG("setPos pos=" << pos);
+ DBUG_ENTER("NdbBlob::setPos");
+ DBUG_PRINT("info", ("pos=%llu", pos));
if (theNullFlag == -1) {
setErrorCode(NdbBlobImpl::ErrState);
- return -1;
+ DBUG_RETURN(-1);
}
if (pos > theLength) {
setErrorCode(NdbBlobImpl::ErrSeek);
- return -1;
+ DBUG_RETURN(-1);
}
thePos = pos;
- return 0;
+ DBUG_RETURN(0);
}
// read/write
@@ -648,7 +631,8 @@ NdbBlob::readData(void* data, Uint32& bytes)
int
NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
{
- DBG("readData [in] bytes=" << bytes);
+ DBUG_ENTER("NdbBlob::readDataPrivate");
+ DBUG_PRINT("info", ("bytes=%u", bytes));
assert(thePos <= theLength);
Uint64 pos = thePos;
if (bytes > theLength - pos)
@@ -668,20 +652,20 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
}
if (len > 0 && thePartSize == 0) {
setErrorCode(NdbBlobImpl::ErrSeek);
- return -1;
+ DBUG_RETURN(-1);
}
if (len > 0) {
assert(pos >= theInlineSize);
Uint32 off = (pos - theInlineSize) % thePartSize;
// partial first block
if (off != 0) {
- DBG("partial first block pos=" << pos << " len=" << len);
+ DBUG_PRINT("info", ("partial first block pos=%llu len=%u", pos, len));
Uint32 part = (pos - theInlineSize) / thePartSize;
if (readParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
// need result now
if (executePendingBlobReads() == -1)
- return -1;
+ DBUG_RETURN(-1);
Uint32 n = thePartSize - off;
if (n > len)
n = len;
@@ -698,7 +682,7 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
Uint32 part = (pos - theInlineSize) / thePartSize;
Uint32 count = len / thePartSize;
if (readParts(buf, part, count) == -1)
- return -1;
+ DBUG_RETURN(-1);
Uint32 n = thePartSize * count;
pos += n;
buf += n;
@@ -707,14 +691,14 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
}
if (len > 0) {
// partial last block
- DBG("partial last block pos=" << pos << " len=" << len);
+ DBUG_PRINT("info", ("partial last block pos=%llu len=%u", pos, len));
assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize);
Uint32 part = (pos - theInlineSize) / thePartSize;
if (readParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
// need result now
if (executePendingBlobReads() == -1)
- return -1;
+ DBUG_RETURN(-1);
memcpy(buf, thePartBuf.data, len);
Uint32 n = len;
pos += n;
@@ -724,8 +708,7 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
assert(len == 0);
thePos = pos;
assert(thePos <= theLength);
- DBG("readData [out]");
- return 0;
+ DBUG_RETURN(0);
}
int
@@ -742,7 +725,8 @@ NdbBlob::writeData(const void* data, Uint32 bytes)
int
NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
{
- DBG("writeData [in] bytes=" << bytes);
+ DBUG_ENTER("NdbBlob::writeDataPrivate");
+ DBUG_PRINT("info", ("bytes=%u", bytes));
assert(thePos <= theLength);
Uint64 pos = thePos;
Uint32 len = bytes;
@@ -766,23 +750,23 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
}
if (len > 0 && thePartSize == 0) {
setErrorCode(NdbBlobImpl::ErrSeek);
- return -1;
+ DBUG_RETURN(-1);
}
if (len > 0) {
assert(pos >= theInlineSize);
Uint32 off = (pos - theInlineSize) % thePartSize;
// partial first block
if (off != 0) {
- DBG("partial first block pos=" << pos << " len=" << len);
+ DBUG_PRINT("info", ("partial first block pos=%llu len=%u", pos, len));
// flush writes to guarantee correct read
if (executePendingBlobWrites() == -1)
- return -1;
+ DBUG_RETURN(-1);
Uint32 part = (pos - theInlineSize) / thePartSize;
if (readParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
// need result now
if (executePendingBlobReads() == -1)
- return -1;
+ DBUG_RETURN(-1);
Uint32 n = thePartSize - off;
if (n > len) {
memset(thePartBuf.data + off + len, theFillChar, n - len);
@@ -790,7 +774,7 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
}
memcpy(thePartBuf.data + off, buf, n);
if (updateParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
pos += n;
buf += n;
len -= n;
@@ -805,10 +789,10 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
for (unsigned i = 0; i < count; i++) {
if (part + i < getPartCount()) {
if (updateParts(buf, part + i, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
if (insertParts(buf, part + i, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
Uint32 n = thePartSize;
pos += n;
@@ -819,30 +803,30 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
}
if (len > 0) {
// partial last block
- DBG("partial last block pos=" << pos << " len=" << len);
+ DBUG_PRINT("info", ("partial last block pos=%llu len=%u", pos, len));
assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize);
Uint32 part = (pos - theInlineSize) / thePartSize;
if (theLength > pos + len) {
// flush writes to guarantee correct read
if (executePendingBlobWrites() == -1)
- return -1;
+ DBUG_RETURN(-1);
if (readParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
// need result now
if (executePendingBlobReads() == -1)
- return -1;
+ DBUG_RETURN(-1);
memcpy(thePartBuf.data, buf, len);
if (updateParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
memcpy(thePartBuf.data, buf, len);
memset(thePartBuf.data + len, theFillChar, thePartSize - len);
if (part < getPartCount()) {
if (updateParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
if (insertParts(thePartBuf.data, part, 1) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
}
Uint32 n = len;
@@ -857,14 +841,14 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
}
thePos = pos;
assert(thePos <= theLength);
- DBG("writeData [out]");
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
{
- DBG("readParts [in] part=" << part << " count=" << count);
+ DBUG_ENTER("NdbBlob::readParts");
+ DBUG_PRINT("info", ("part=%u count=%u", part, count));
Uint32 n = 0;
while (n < count) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -873,7 +857,7 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
setPartKeyValue(tOp, part + n) == -1 ||
tOp->getValue((Uint32)3, buf) == NULL) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
@@ -881,13 +865,14 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
theNdbCon->thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
{
- DBG("insertParts [in] part=" << part << " count=" << count);
+ DBUG_ENTER("NdbBlob::insertParts");
+ DBUG_PRINT("info", ("part=%u count=%u", part, count));
Uint32 n = 0;
while (n < count) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -896,7 +881,7 @@ NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
setPartKeyValue(tOp, part + n) == -1 ||
tOp->setValue((Uint32)3, buf) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
@@ -904,13 +889,14 @@ NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
theNdbCon->thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count)
{
- DBG("updateParts [in] part=" << part << " count=" << count);
+ DBUG_ENTER("NdbBlob::updateParts");
+ DBUG_PRINT("info", ("part=%u count=%u", part, count));
Uint32 n = 0;
while (n < count) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -919,7 +905,7 @@ NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count)
setPartKeyValue(tOp, part + n) == -1 ||
tOp->setValue((Uint32)3, buf) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
@@ -927,13 +913,14 @@ NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count)
thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
theNdbCon->thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::deleteParts(Uint32 part, Uint32 count)
{
- DBG("deleteParts [in] part=" << part << " count=" << count);
+ DBUG_ENTER("NdbBlob::deleteParts");
+ DBUG_PRINT("info", ("part=%u count=%u", part, count));
Uint32 n = 0;
while (n < count) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -941,14 +928,14 @@ NdbBlob::deleteParts(Uint32 part, Uint32 count)
tOp->deleteTuple() == -1 ||
setPartKeyValue(tOp, part + n) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
n++;
thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
}
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -958,7 +945,8 @@ NdbBlob::deleteParts(Uint32 part, Uint32 count)
int
NdbBlob::deletePartsUnknown(Uint32 part)
{
- DBG("deletePartsUnknown [in] part=" << part << " count=all");
+ DBUG_ENTER("NdbBlob::deletePartsUnknown");
+ DBUG_PRINT("info", ("part=%u count=all", part));
static const unsigned maxbat = 256;
static const unsigned minbat = 1;
unsigned bat = minbat;
@@ -974,26 +962,25 @@ NdbBlob::deletePartsUnknown(Uint32 part)
tOp->deleteTuple() == -1 ||
setPartKeyValue(tOp, part + count + n) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption= NdbTransaction::AO_IgnoreError;
n++;
}
- DBG("deletePartsUnknown: executeNoBlobs [in] bat=" << bat);
+ DBUG_PRINT("info", ("bat=%u", bat));
if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
- return -1;
- DBG("deletePartsUnknown: executeNoBlobs [out]");
+ DBUG_RETURN(-1);
n = 0;
while (n < bat) {
NdbOperation* tOp = tOpList[n];
if (tOp->theError.code != 0) {
if (tOp->theError.code != 626) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
// first non-existent part
- DBG("deletePartsUnknown [out] count=" << count);
- return 0;
+ DBUG_PRINT("info", ("count=%u", count));
+ DBUG_RETURN(0);
}
n++;
count++;
@@ -1009,31 +996,29 @@ NdbBlob::deletePartsUnknown(Uint32 part)
int
NdbBlob::executePendingBlobReads()
{
+ DBUG_ENTER("NdbBlob::executePendingBlobReads");
Uint8 flags = (1 << NdbOperation::ReadRequest);
if (thePendingBlobOps & flags) {
- DBG("executePendingBlobReads: executeNoBlobs [in]");
if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
- return -1;
- DBG("executePendingBlobReads: executeNoBlobs [out]");
+ DBUG_RETURN(-1);
thePendingBlobOps = 0;
theNdbCon->thePendingBlobOps = 0;
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbBlob::executePendingBlobWrites()
{
+ DBUG_ENTER("NdbBlob::executePendingBlobWrites");
Uint8 flags = 0xFF & ~(1 << NdbOperation::ReadRequest);
if (thePendingBlobOps & flags) {
- DBG("executePendingBlobWrites: executeNoBlobs [in]");
if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
- return -1;
- DBG("executePendingBlobWrites: executeNoBlobs [out]");
+ DBUG_RETURN(-1);
thePendingBlobOps = 0;
theNdbCon->thePendingBlobOps = 0;
}
- return 0;
+ DBUG_RETURN(0);
}
// callbacks
@@ -1041,15 +1026,14 @@ NdbBlob::executePendingBlobWrites()
int
NdbBlob::invokeActiveHook()
{
- DBG("invokeActiveHook [in]");
+ DBUG_ENTER("NdbBlob::invokeActiveHook");
assert(theState == Active && theActiveHook != NULL);
int ret = (*theActiveHook)(this, theActiveHookArg);
- DBG("invokeActiveHook [out] ret=" << ret);
if (ret != 0) {
// no error is set on blob level
- return -1;
+ DBUG_RETURN(-1);
}
- return 0;
+ DBUG_RETURN(0);
}
// blob handle maintenance
@@ -1062,6 +1046,8 @@ NdbBlob::invokeActiveHook()
int
NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn)
{
+ DBUG_ENTER("NdbBlob::atPrepare");
+ DBUG_PRINT("info", ("this=%p op=%p con=%p", this, anOp, aCon));
assert(theState == Idle);
// ndb api stuff
theNdb = anOp->theNdb;
@@ -1070,7 +1056,6 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
theTable = anOp->m_currentTable;
theAccessTable = anOp->m_accessTable;
theColumn = aColumn;
- DBG("atPrepare [in]");
NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
switch (theColumn->getType()) {
case NdbDictionary::Column::Blob:
@@ -1083,7 +1068,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
break;
default:
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
// sizes
theInlineSize = theColumn->getInlineSize();
@@ -1101,7 +1086,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
bc->getType() != partType ||
bc->getLength() != (int)thePartSize) {
setErrorCode(NdbBlobImpl::ErrTable);
- return -1;
+ DBUG_RETURN(-1);
}
theBlobTable = &NdbTableImpl::getImpl(*bt);
}
@@ -1122,7 +1107,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
unsigned size = theTable->m_keyLenInWords;
if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
}
if (isIndexOp()) {
@@ -1131,13 +1116,13 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
unsigned size = theAccessTable->m_keyLenInWords;
if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
}
if (isReadOp()) {
// add read of head+inline in this op
if (getHeadInlineValue(theNdbOp) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
if (isInsertOp()) {
// becomes NULL unless set before execute
@@ -1155,16 +1140,15 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
if (isScanOp()) {
// add read of head+inline in this op
if (getHeadInlineValue(theNdbOp) == -1)
- return -1;
+ DBUG_RETURN(-1);
supportedOp = true;
}
if (! supportedOp) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
setState(Prepared);
- DBG("atPrepare [out]");
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -1177,9 +1161,10 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl
int
NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
{
- DBG("preExecute [in]");
+ DBUG_ENTER("NdbBlob::preExecute");
+ DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon));
if (theState == Invalid)
- return -1;
+ DBUG_RETURN(-1);
assert(theState == Prepared);
// handle different operation types
assert(isKeyOp());
@@ -1197,7 +1182,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
Uint32 bytes = theGetSetBytes - theInlineSize;
assert(thePos == theInlineSize);
if (writeDataPrivate(buf, bytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
if (theHeadInlineUpdateFlag) {
// add an operation to update head+inline
NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
@@ -1206,9 +1191,9 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
setTableKeyValue(tOp) == -1 ||
setHeadInlineValue(tOp) == -1) {
setErrorCode(NdbBlobImpl::ErrAbort);
- return -1;
+ DBUG_RETURN(-1);
}
- DBG("add op to update head+inline");
+ DBUG_PRINT("info", ("add op to update head+inline"));
}
}
}
@@ -1221,7 +1206,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
setTableKeyValue(tOp) == -1 ||
getHeadInlineValue(tOp) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
if (isWriteOp()) {
tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
@@ -1229,7 +1214,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
theHeadInlineReadOp = tOp;
// execute immediately
batch = true;
- DBG("add op before to read head+inline");
+ DBUG_PRINT("info", ("add op before to read head+inline"));
}
}
if (isIndexOp()) {
@@ -1245,7 +1230,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
setAccessKeyValue(tOp) == -1 ||
tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
} else {
NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp);
@@ -1254,11 +1239,11 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
setAccessKeyValue(tOp) == -1 ||
getTableKeyValue(tOp) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
}
}
- DBG("added op before to read table key");
+ DBUG_PRINT("info", ("added op before to read table key"));
if (isUpdateOp() || isDeleteOp()) {
// add op before this one to read head+inline via index
NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp);
@@ -1267,7 +1252,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
setAccessKeyValue(tOp) == -1 ||
getHeadInlineValue(tOp) == -1) {
setErrorCode(tOp);
- return -1;
+ DBUG_RETURN(-1);
}
if (isWriteOp()) {
tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
@@ -1275,7 +1260,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
theHeadInlineReadOp = tOp;
// execute immediately
batch = true;
- DBG("added index op before to read head+inline");
+ DBUG_PRINT("info", ("added index op before to read head+inline"));
}
if (isWriteOp()) {
// XXX until IgnoreError fixed for index op
@@ -1293,10 +1278,10 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
n = theInlineSize;
assert(thePos == 0);
if (writeDataPrivate(theSetBuf, n) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
if (setHeadInlineValue(theNdbOp) == -1)
- return -1;
+ DBUG_RETURN(-1);
// the read op before us may overwrite
theHeadInlineCopyBuf.copyfrom(theHeadInlineBuf);
}
@@ -1305,8 +1290,8 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
// need blob head for callback
batch = true;
}
- DBG("preExecute [out] batch=" << batch);
- return 0;
+ DBUG_PRINT("info", ("batch=%u", batch));
+ DBUG_RETURN(0);
}
/*
@@ -1318,13 +1303,14 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
int
NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
{
- DBG("postExecute [in] type=" << anExecType);
+ DBUG_ENTER("NdbBlob::postExecute");
+ DBUG_PRINT("info", ("this=%p op=%p con=%p anExecType=%u", this, theNdbOp, theNdbCon, anExecType));
if (theState == Invalid)
- return -1;
+ DBUG_RETURN(-1);
if (theState == Active) {
setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
- DBG("postExecute [skip]");
- return 0;
+ DBUG_PRINT("info", ("skip active"));
+ DBUG_RETURN(0);
}
assert(theState == Prepared);
setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
@@ -1340,14 +1326,14 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
if (isReadOp()) {
getHeadFromRecAttr();
if (setPos(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
if (theGetFlag) {
assert(theGetSetBytes == 0 || theGetBuf != 0);
assert(theGetSetBytes <= theInlineSize ||
anExecType == NdbTransaction::NoCommit);
Uint32 bytes = theGetSetBytes;
if (readDataPrivate(theGetBuf, bytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
}
if (isUpdateOp()) {
@@ -1357,13 +1343,13 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
// setValue overwrites everything
if (theSetBuf != NULL) {
if (truncate(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
assert(thePos == 0);
if (writeDataPrivate(theSetBuf, theGetSetBytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
} else {
if (setNull() == -1)
- return -1;
+ DBUG_RETURN(-1);
}
}
}
@@ -1374,9 +1360,9 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
Uint64 tLength = theLength;
Uint64 tPos = thePos;
getHeadFromRecAttr();
- DBG("tuple found");
+ DBUG_PRINT("info", ("tuple found"));
if (truncate(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
// restore previous head+inline
theHeadInlineBuf.copyfrom(theHeadInlineCopyBuf);
theNullFlag = tNullFlag;
@@ -1385,16 +1371,16 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
} else {
if (theHeadInlineReadOp->theError.code != 626) {
setErrorCode(theHeadInlineReadOp);
- return -1;
+ DBUG_RETURN(-1);
}
- DBG("tuple not found");
+ DBUG_PRINT("info", ("tuple not found"));
/*
* Read found no tuple but it is possible that a tuple was
* created after the read by another transaction. Delete all
* blob parts which may exist.
*/
if (deletePartsUnknown(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
if (theSetFlag && theGetSetBytes > theInlineSize) {
assert(theSetBuf != NULL);
@@ -1402,33 +1388,33 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
Uint32 bytes = theGetSetBytes - theInlineSize;
assert(thePos == theInlineSize);
if (writeDataPrivate(buf, bytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
}
if (isWriteOp() && isIndexOp()) {
// XXX until IgnoreError fixed for index op
if (deletePartsUnknown(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
if (theSetFlag && theGetSetBytes > theInlineSize) {
assert(theSetBuf != NULL);
const char* buf = theSetBuf + theInlineSize;
Uint32 bytes = theGetSetBytes - theInlineSize;
assert(thePos == theInlineSize);
if (writeDataPrivate(buf, bytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
}
if (isDeleteOp()) {
assert(anExecType == NdbTransaction::NoCommit);
getHeadFromRecAttr();
if (deleteParts(0, getPartCount()) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
// activation callback
if (theActiveHook != NULL) {
if (invokeActiveHook() == -1)
- return -1;
+ DBUG_RETURN(-1);
}
if (anExecType == NdbTransaction::NoCommit && theHeadInlineUpdateFlag) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
@@ -1437,13 +1423,12 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
setTableKeyValue(tOp) == -1 ||
setHeadInlineValue(tOp) == -1) {
setErrorCode(NdbBlobImpl::ErrAbort);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
- DBG("added op to update head+inline");
+ DBUG_PRINT("info", ("added op to update head+inline"));
}
- DBG("postExecute [out]");
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -1453,9 +1438,10 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
int
NdbBlob::preCommit()
{
- DBG("preCommit [in]");
+ DBUG_ENTER("NdbBlob::preCommit");
+ DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon));
if (theState == Invalid)
- return -1;
+ DBUG_RETURN(-1);
assert(theState == Active);
assert(isKeyOp());
if (isInsertOp() || isUpdateOp() || isWriteOp()) {
@@ -1467,14 +1453,13 @@ NdbBlob::preCommit()
setTableKeyValue(tOp) == -1 ||
setHeadInlineValue(tOp) == -1) {
setErrorCode(NdbBlobImpl::ErrAbort);
- return -1;
+ DBUG_RETURN(-1);
}
tOp->m_abortOption = NdbTransaction::AbortOnError;
- DBG("added op to update head+inline");
+ DBUG_PRINT("info", ("added op to update head+inline"));
}
}
- DBG("preCommit [out]");
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -1483,35 +1468,35 @@ NdbBlob::preCommit()
int
NdbBlob::atNextResult()
{
- DBG("atNextResult [in]");
+ DBUG_ENTER("NdbBlob::atNextResult");
+ DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon));
if (theState == Invalid)
- return -1;
+ DBUG_RETURN(-1);
assert(isScanOp());
// get primary key
{ Uint32* data = (Uint32*)theKeyBuf.data;
unsigned size = theTable->m_keyLenInWords;
if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
- return -1;
+ DBUG_RETURN(-1);
}
}
getHeadFromRecAttr();
if (setPos(0) == -1)
- return -1;
+ DBUG_RETURN(-1);
if (theGetFlag) {
assert(theGetSetBytes == 0 || theGetBuf != 0);
Uint32 bytes = theGetSetBytes;
if (readDataPrivate(theGetBuf, bytes) == -1)
- return -1;
+ DBUG_RETURN(-1);
}
setState(Active);
// activation callback
if (theActiveHook != NULL) {
if (invokeActiveHook() == -1)
- return -1;
+ DBUG_RETURN(-1);
}
- DBG("atNextResult [out]");
- return 0;
+ DBUG_RETURN(0);
}
// misc
@@ -1527,13 +1512,15 @@ NdbBlob::getColumn()
void
NdbBlob::setErrorCode(int anErrorCode, bool invalidFlag)
{
- DBG("setErrorCode code=" << anErrorCode);
+ DBUG_ENTER("NdbBlob::setErrorCode");
+ DBUG_PRINT("info", ("this=%p code=%u", this, anErrorCode));
theError.code = anErrorCode;
// conditionally copy error to operation level
if (theNdbOp != NULL && theNdbOp->theError.code == 0)
theNdbOp->setErrorCode(theError.code);
if (invalidFlag)
setState(Invalid);
+ DBUG_VOID_RETURN;
}
void
diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp
index 4cc47543cec..79b6fb4c0e8 100644
--- a/ndb/src/ndbapi/NdbDictionary.cpp
+++ b/ndb/src/ndbapi/NdbDictionary.cpp
@@ -773,9 +773,11 @@ NdbDictionary::Dictionary::getTable(const char * name) const
void
NdbDictionary::Dictionary::invalidateTable(const char * name){
+ DBUG_ENTER("NdbDictionaryImpl::invalidateTable");
NdbTableImpl * t = m_impl.getTable(name);
if(t)
m_impl.invalidateObject(* t);
+ DBUG_VOID_RETURN;
}
void
@@ -811,11 +813,13 @@ NdbDictionary::Dictionary::getIndex(const char * indexName,
void
NdbDictionary::Dictionary::invalidateIndex(const char * indexName,
const char * tableName){
+ DBUG_ENTER("NdbDictionaryImpl::invalidateIndex");
NdbIndexImpl * i = m_impl.getIndex(indexName, tableName);
if(i) {
assert(i->m_table != 0);
m_impl.invalidateObject(* i->m_table);
}
+ DBUG_VOID_RETURN;
}
void
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index 6ecaf54b888..34d1614d043 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -735,19 +735,19 @@ NdbDictionaryImpl::~NdbDictionaryImpl()
}
Ndb_local_table_info *
-NdbDictionaryImpl::fetchGlobalTableImpl(const char * internalTableName)
+NdbDictionaryImpl::fetchGlobalTableImpl(const BaseString& internalTableName)
{
NdbTableImpl *impl;
m_globalHash->lock();
- impl = m_globalHash->get(internalTableName);
+ impl = m_globalHash->get(internalTableName.c_str());
m_globalHash->unlock();
if (impl == 0){
impl = m_receiver.getTable(internalTableName,
m_ndb.usingFullyQualifiedNames());
m_globalHash->lock();
- m_globalHash->put(internalTableName, impl);
+ m_globalHash->put(internalTableName.c_str(), impl);
m_globalHash->unlock();
if(impl == 0){
@@ -758,7 +758,7 @@ NdbDictionaryImpl::fetchGlobalTableImpl(const char * internalTableName)
Ndb_local_table_info *info=
Ndb_local_table_info::create(impl, m_local_table_data_size);
- m_localHash.put(internalTableName, info);
+ m_localHash.put(internalTableName.c_str(), info);
m_ndb.theFirstTupleId[impl->getTableId()] = ~0;
m_ndb.theLastTupleId[impl->getTableId()] = ~0;
@@ -806,14 +806,13 @@ NdbDictionaryImpl::setTransporter(class Ndb* ndb,
return false;
}
-NdbTableImpl *
-NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index,
+NdbTableImpl *
+NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index,
NdbTableImpl * table)
{
- const char * internalName =
- m_ndb.internalizeIndexName(table, index->getName());
-
- return getTable(m_ndb.externalizeTableName(internalName));
+ const BaseString internalName(
+ m_ndb.internalize_index_name(table, index->getName()));
+ return getTable(m_ndb.externalizeTableName(internalName.c_str()));
}
#if 0
@@ -1055,7 +1054,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal,
}
DBUG_RETURN(-1);
}
-
+#if 0
/*
Get dictionary information for a table using table id as reference
@@ -1079,6 +1078,7 @@ NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames)
return getTable(&tSignal, 0, 0, fullyQualifiedNames);
}
+#endif
/*
@@ -1090,36 +1090,31 @@ NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames)
*/
NdbTableImpl *
-NdbDictInterface::getTable(const char * name, bool fullyQualifiedNames)
+NdbDictInterface::getTable(const BaseString& name, bool fullyQualifiedNames)
{
NdbApiSignal tSignal(m_reference);
GetTabInfoReq* const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
- const Uint32 str_len= strlen(name) + 1; // NULL terminated
- const Uint32 str_len_words= (str_len + 3) / 4; // Size in words
-
- if (str_len > MAX_SECTION_SIZE)
- {
- m_error.code= 4307;
- return 0;
- }
-
- m_namebuf.clear();
- m_namebuf.grow(str_len_words*4); // Word size aligned number of bytes
- m_namebuf.append(name, str_len);
+ const Uint32 namelen= name.length() + 1; // NULL terminated
+ const Uint32 namelen_words= (namelen + 3) >> 2; // Size in words
req->senderRef= m_reference;
req->senderData= 0;
req->requestType=
GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
- req->tableNameLen= str_len;
+ req->tableNameLen= namelen;
tSignal.theReceiversBlockNumber= DBDICT;
tSignal.theVerId_signalNumber= GSN_GET_TABINFOREQ;
tSignal.theLength= GetTabInfoReq::SignalLength;
+ // Copy name to m_buffer to get a word sized buffer
+ m_buffer.clear();
+ m_buffer.grow(namelen_words*4);
+ m_buffer.append(name.c_str(), namelen);
+
LinearSectionPtr ptr[1];
- ptr[0].p= (Uint32*)m_namebuf.get_data();
- ptr[0].sz= str_len_words;
+ ptr[0].p= (Uint32*)m_buffer.get_data();
+ ptr[0].sz= namelen_words;
return getTable(&tSignal, ptr, 1, fullyQualifiedNames);
}
@@ -1463,7 +1458,7 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t)
return 0;
// update table def from DICT
Ndb_local_table_info *info=
- get_local_table_info(t.m_internalName.c_str(),false);
+ get_local_table_info(t.m_internalName,false);
if (info == NULL) {
m_error.code= 709;
return -1;
@@ -1490,7 +1485,7 @@ NdbDictionaryImpl::createBlobTables(NdbTableImpl &t)
return -1;
// Save BLOB table handle
Ndb_local_table_info *info=
- get_local_table_info(bt.m_internalName.c_str(), false);
+ get_local_table_info(bt.m_internalName, false);
if (info == 0) {
return -1;
}
@@ -1534,12 +1529,11 @@ NdbDictInterface::createTable(Ndb & ndb,
int NdbDictionaryImpl::alterTable(NdbTableImpl &impl)
{
- BaseString internalName = impl.m_internalName;
+ BaseString internalName(impl.m_internalName);
const char * originalInternalName = internalName.c_str();
- BaseString externalName = impl.m_externalName;
DBUG_ENTER("NdbDictionaryImpl::alterTable");
- if(!get_local_table_info(originalInternalName, false)){
+ if(!get_local_table_info(internalName, false)){
m_error.code= 709;
DBUG_RETURN(-1);
}
@@ -1594,14 +1588,14 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
//validate();
//aggregate();
- const char * internalName =
- ndb.internalizeTableName(impl.m_externalName.c_str());
+ const BaseString internalName(
+ ndb.internalize_table_name(impl.m_externalName.c_str()));
impl.m_internalName.assign(internalName);
UtilBufferWriter w(m_buffer);
DictTabInfo::Table tmpTab; tmpTab.init();
- BaseString::snprintf(tmpTab.TableName,
- sizeof(tmpTab.TableName),
- internalName);
+ BaseString::snprintf(tmpTab.TableName,
+ sizeof(tmpTab.TableName),
+ internalName.c_str());
bool haveAutoIncrement = false;
Uint64 autoIncrementValue = 0;
@@ -1865,14 +1859,14 @@ NdbDictionaryImpl::dropTable(const char * name)
// If table stored in cache is incompatible with the one in the kernel
// we must clear the cache and try again
if (ret == INCOMPATIBLE_VERSION) {
- const char * internalTableName = m_ndb.internalizeTableName(name);
+ const BaseString internalTableName(m_ndb.internalize_table_name(name));
- DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName));
- m_localHash.drop(internalTableName);
+ DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName.c_str()));
+ m_localHash.drop(internalTableName.c_str());
m_globalHash->lock();
tab->m_status = NdbDictionary::Object::Invalid;
m_globalHash->drop(tab);
- m_globalHash->unlock();
+ m_globalHash->unlock();
DBUG_RETURN(dropTable(name));
}
@@ -2013,13 +2007,14 @@ int
NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl)
{
const char * internalTableName = impl.m_internalName.c_str();
-
- m_localHash.drop(internalTableName);
+ DBUG_ENTER("NdbDictionaryImpl::invalidateObject");
+ DBUG_PRINT("enter", ("internal_name: %s", internalTableName));
+ m_localHash.drop(internalTableName);
m_globalHash->lock();
impl.m_status = NdbDictionary::Object::Invalid;
m_globalHash->drop(&impl);
m_globalHash->unlock();
- return 0;
+ DBUG_RETURN(0);
}
int
@@ -2038,8 +2033,8 @@ NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl)
* Get index info
*/
NdbIndexImpl*
-NdbDictionaryImpl::getIndexImpl(const char * externalName,
- const char * internalName)
+NdbDictionaryImpl::getIndexImpl(const char * externalName,
+ const BaseString& internalName)
{
Ndb_local_table_info * info = get_local_table_info(internalName,
false);
@@ -2055,21 +2050,11 @@ NdbDictionaryImpl::getIndexImpl(const char * externalName,
return 0;
}
- /*
- * internalName may be pointer to m_ndb.theImpl->m_internalname.c_str()
- * and may get deallocated in next call.
- *
- * Passing around pointers to volatile internal members may not be
- * optimal. Suggest use BaseString instances passed by value.
- */
-
- BaseString save_me(internalName);
NdbTableImpl* prim = getTable(tab->m_primaryTable.c_str());
if(prim == 0){
m_error.code = 4243;
return 0;
}
- internalName = save_me.c_str();
/**
* Create index impl
@@ -2175,12 +2160,11 @@ NdbDictInterface::createIndex(Ndb & ndb,
m_error.code = 4241;
return -1;
}
- const char * internalName =
- ndb.internalizeIndexName(&table, impl.getName());
-
+ const BaseString internalName(
+ ndb.internalize_index_name(&table, impl.getName()));
impl.m_internalName.assign(internalName);
- w.add(DictTabInfo::TableName, internalName);
+ w.add(DictTabInfo::TableName, internalName.c_str());
w.add(DictTabInfo::TableLoggedFlag, impl.m_logging);
NdbApiSignal tSignal(m_reference);
@@ -2286,20 +2270,20 @@ NdbDictionaryImpl::dropIndex(const char * indexName,
// If index stored in cache is incompatible with the one in the kernel
// we must clear the cache and try again
if (ret == INCOMPATIBLE_VERSION) {
- const char * internalIndexName = (tableName)
+ const BaseString internalIndexName((tableName)
?
- m_ndb.internalizeIndexName(getTable(tableName), indexName)
+ m_ndb.internalize_index_name(getTable(tableName), indexName)
:
- m_ndb.internalizeTableName(indexName); // Index is also a table
-
- m_localHash.drop(internalIndexName);
+ m_ndb.internalize_table_name(indexName)); // Index is also a table
+
+ m_localHash.drop(internalIndexName.c_str());
m_globalHash->lock();
idx->m_table->m_status = NdbDictionary::Object::Invalid;
m_globalHash->drop(idx->m_table);
- m_globalHash->unlock();
+ m_globalHash->unlock();
return dropIndex(indexName, tableName);
}
-
+
return ret;
}
@@ -2315,19 +2299,19 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName)
return -1;
}
- const char * internalIndexName = (tableName)
+ const BaseString internalIndexName((tableName)
?
- m_ndb.internalizeIndexName(getTable(tableName), indexName)
+ m_ndb.internalize_index_name(getTable(tableName), indexName)
:
- m_ndb.internalizeTableName(indexName); // Index is also a table
+ m_ndb.internalize_table_name(indexName)); // Index is also a table
if(impl.m_status == NdbDictionary::Object::New){
return dropIndex(indexName, tableName);
}
-
+
int ret = m_receiver.dropIndex(impl, *timpl);
if(ret == 0){
- m_localHash.drop(internalIndexName);
+ m_localHash.drop(internalIndexName.c_str());
m_globalHash->lock();
impl.m_table->m_status = NdbDictionary::Object::Invalid;
m_globalHash->drop(impl.m_table);
@@ -2532,8 +2516,12 @@ NdbDictInterface::createEvent(class Ndb & ndb,
w.add(SimpleProperties::StringValue, evnt.m_externalName.c_str());
if (getFlag == 0)
+ {
+ const BaseString internal_tabname(
+ ndb.internalize_table_name(evnt.m_tableName.c_str()));
w.add(SimpleProperties::StringValue,
- ndb.internalizeTableName(evnt.m_tableName.c_str()));
+ internal_tabname.c_str());
+ }
LinearSectionPtr ptr[1];
ptr[0].p = (Uint32*)m_buffer.get_data();
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp
index 7e3e3b19294..754d0000718 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp
@@ -19,7 +19,6 @@
#include <ndb_types.h>
#include <kernel_types.h>
-#include <ndb_limits.h>
#include <NdbError.hpp>
#include <BaseString.hpp>
#include <Vector.hpp>
@@ -309,8 +308,8 @@ public:
int listObjects(NdbDictionary::Dictionary::List& list, Uint32 requestData, bool fullyQualifiedNames);
int listObjects(NdbApiSignal* signal);
- NdbTableImpl * getTable(int tableId, bool fullyQualifiedNames);
- NdbTableImpl * getTable(const char * name, bool fullyQualifiedNames);
+/* NdbTableImpl * getTable(int tableId, bool fullyQualifiedNames); */
+ NdbTableImpl * getTable(const BaseString& name, bool fullyQualifiedNames);
NdbTableImpl * getTable(class NdbApiSignal * signal,
LinearSectionPtr ptr[3],
Uint32 noOfSections, bool fullyQualifiedNames);
@@ -368,8 +367,6 @@ private:
Uint32 m_fragmentId;
UtilBuffer m_buffer;
- // Buffer used when requesting a table by name
- UtilBuffer m_namebuf;
};
class NdbDictionaryImpl : public NdbDictionary::Dictionary {
@@ -406,13 +403,12 @@ public:
int listObjects(List& list, NdbDictionary::Object::Type type);
int listIndexes(List& list, Uint32 indexId);
-
+
NdbTableImpl * getTable(const char * tableName, void **data= 0);
- Ndb_local_table_info * get_local_table_info(const char * internalName,
- bool do_add_blob_tables);
+ Ndb_local_table_info* get_local_table_info(
+ const BaseString& internalTableName, bool do_add_blob_tables);
NdbIndexImpl * getIndex(const char * indexName,
const char * tableName);
- NdbIndexImpl * getIndexImpl(const char * name, const char * internalName);
NdbEventImpl * getEvent(const char * eventName);
NdbEventImpl * getEventImpl(const char * internalName);
@@ -430,7 +426,9 @@ public:
NdbDictInterface m_receiver;
Ndb & m_ndb;
private:
- Ndb_local_table_info * fetchGlobalTableImpl(const char * internalName);
+ NdbIndexImpl * getIndexImpl(const char * name,
+ const BaseString& internalName);
+ Ndb_local_table_info * fetchGlobalTableImpl(const BaseString& internalName);
};
inline
@@ -638,26 +636,27 @@ NdbDictionaryImpl::getImpl(const NdbDictionary::Dictionary & t){
*/
inline
-NdbTableImpl *
-NdbDictionaryImpl::getTable(const char * tableName, void **data)
+NdbTableImpl *
+NdbDictionaryImpl::getTable(const char * table_name, void **data)
{
+ const BaseString internal_tabname(m_ndb.internalize_table_name(table_name));
Ndb_local_table_info *info=
- get_local_table_info(m_ndb.internalizeTableName(tableName), true);
- if (info == 0) {
+ get_local_table_info(internal_tabname, true);
+ if (info == 0)
return 0;
- }
- if (data) {
+
+ if (data)
*data= info->m_local_data;
- }
+
return info->m_table_impl;
}
inline
Ndb_local_table_info *
-NdbDictionaryImpl::get_local_table_info(const char * internalTableName,
+NdbDictionaryImpl::get_local_table_info(const BaseString& internalTableName,
bool do_add_blob_tables)
{
- Ndb_local_table_info *info= m_localHash.get(internalTableName);
+ Ndb_local_table_info *info= m_localHash.get(internalTableName.c_str());
if (info == 0) {
info= fetchGlobalTableImpl(internalTableName);
if (info == 0) {
@@ -672,34 +671,35 @@ NdbDictionaryImpl::get_local_table_info(const char * internalTableName,
inline
NdbIndexImpl *
-NdbDictionaryImpl::getIndex(const char * indexName,
- const char * tableName)
+NdbDictionaryImpl::getIndex(const char * index_name,
+ const char * table_name)
{
- if (tableName || m_ndb.usingFullyQualifiedNames()) {
- const char * internalIndexName = 0;
- if (tableName) {
- NdbTableImpl * t = getTable(tableName);
- if (t != 0)
- internalIndexName = m_ndb.internalizeIndexName(t, indexName);
- } else {
- internalIndexName =
- m_ndb.internalizeTableName(indexName); // Index is also a table
- }
- if (internalIndexName) {
- Ndb_local_table_info * info = get_local_table_info(internalIndexName,
- false);
- if (info) {
- NdbTableImpl * tab = info->m_table_impl;
+ if (table_name || m_ndb.usingFullyQualifiedNames())
+ {
+ const BaseString internal_indexname(
+ (table_name)
+ ?
+ m_ndb.internalize_index_name(getTable(table_name), index_name)
+ :
+ m_ndb.internalize_table_name(index_name)); // Index is also a table
+
+ if (internal_indexname.length())
+ {
+ Ndb_local_table_info * info=
+ get_local_table_info(internal_indexname, false);
+ if (info)
+ {
+ NdbTableImpl * tab= info->m_table_impl;
if (tab->m_index == 0)
- tab->m_index = getIndexImpl(indexName, internalIndexName);
+ tab->m_index= getIndexImpl(index_name, internal_indexname);
if (tab->m_index != 0)
- tab->m_index->m_table = tab;
+ tab->m_index->m_table= tab;
return tab->m_index;
}
}
}
- m_error.code = 4243;
+ m_error.code= 4243;
return 0;
}
diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp
index f4ce76fee61..d73b8afe10c 100644
--- a/ndb/src/ndbapi/NdbImpl.hpp
+++ b/ndb/src/ndbapi/NdbImpl.hpp
@@ -65,7 +65,6 @@ public:
BaseString m_schemaname; // Schema name
BaseString m_prefix; // Buffer for preformatted internal name <db>/<schema>/
- BaseString m_internalname;
void update_prefix()
{
@@ -73,23 +72,6 @@ public:
m_schemaname.c_str(), table_name_separator);
}
- const char* internalize_table_name(const char* ext_name)
- {
- // Internal table name format <db>/<schema>/<table>
- return m_internalname.assign(m_prefix).append(ext_name).c_str();
- }
-
- const char* internalize_index_name(const NdbTableImpl *table,
- const char* ext_name)
- {
- // Internal index name format <db>/<schema>/<tabid>/<table>
- return m_internalname.assign(m_prefix).appfmt("%d%c%s",
- table->m_tableId,
- table_name_separator,
- ext_name).c_str();
- }
-
-
};
#ifdef VM_TRACE
diff --git a/ndb/src/ndbapi/NdbLinHash.hpp b/ndb/src/ndbapi/NdbLinHash.hpp
index f245a261a04..05670534c95 100644
--- a/ndb/src/ndbapi/NdbLinHash.hpp
+++ b/ndb/src/ndbapi/NdbLinHash.hpp
@@ -192,7 +192,7 @@ template <class C>
inline
Int32
NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data )
-{
+{
const Uint32 hash = Hash(str, len);
int dir, seg;
getBucket(hash, &dir, &seg);
@@ -219,8 +219,9 @@ NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data )
chain->localkey1 = lkey1;
chain->next = 0;
chain->theData = data;
+ len++; // Null terminated
chain->str = new Uint32[((len + 3) >> 2)];
- memcpy( &chain->str[0], str, len );
+ memcpy( &chain->str[0], str, len);
if (oldChain != 0)
oldChain->next = chain;
else
diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp
index 6898639e059..e0a480e02f7 100644
--- a/ndb/src/ndbapi/NdbScanOperation.cpp
+++ b/ndb/src/ndbapi/NdbScanOperation.cpp
@@ -89,15 +89,18 @@ int
NdbScanOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection)
{
m_transConnection = myConnection;
- //NdbTransaction* aScanConnection = theNdb->startTransaction(myConnection);
+ //NdbConnection* aScanConnection = theNdb->startTransaction(myConnection);
+ theNdb->theRemainingStartTransactions++; // will be checked in hupp...
NdbTransaction* aScanConnection = theNdb->hupp(myConnection);
if (!aScanConnection){
+ theNdb->theRemainingStartTransactions--;
setErrorCodeAbort(theNdb->getNdbError().code);
return -1;
}
// NOTE! The hupped trans becomes the owner of the operation
if(NdbOperation::init(tab, aScanConnection) != 0){
+ theNdb->theRemainingStartTransactions--;
return -1;
}
@@ -675,6 +678,7 @@ void NdbScanOperation::close(bool forceSend, bool releaseOp)
tCon->theScanningOp = 0;
theNdb->closeTransaction(tCon);
+ theNdb->theRemainingStartTransactions--;
DBUG_VOID_RETURN;
}
diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp
index d0d664c9a3c..675c9383c6e 100644
--- a/ndb/src/ndbapi/NdbTransaction.cpp
+++ b/ndb/src/ndbapi/NdbTransaction.cpp
@@ -25,7 +25,6 @@
#include "TransporterFacade.hpp"
#include "API.hpp"
#include "NdbBlob.hpp"
-#include <ndb_limits.h>
#include <signaldata/TcKeyConf.hpp>
#include <signaldata/TcIndx.hpp>
@@ -1287,10 +1286,9 @@ NdbTransaction::getNdbIndexOperation(const char* anIndexName,
{
// This unique index is defined from SQL level
static const char* uniqueSuffix= "$unique";
- char uniqueIndexName[MAX_TAB_NAME_SIZE];
-
- strxnmov(uniqueIndexName, MAX_TAB_NAME_SIZE, anIndexName, uniqueSuffix, NullS);
- index = theNdb->theDictionary->getIndex(uniqueIndexName,
+ BaseString uniqueIndexName(anIndexName);
+ uniqueIndexName.append(uniqueSuffix);
+ index = theNdb->theDictionary->getIndex(uniqueIndexName.c_str(),
aTableName);
}
else
diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp
index c550701229c..fee6f0930ad 100644
--- a/ndb/src/ndbapi/Ndbif.cpp
+++ b/ndb/src/ndbapi/Ndbif.cpp
@@ -107,12 +107,10 @@ Ndb::init(int aMaxNoOfTransactions)
goto error_handler;
}
- tMaxNoOfTransactions = aMaxNoOfTransactions * 3;
- if (tMaxNoOfTransactions > 1024) {
- tMaxNoOfTransactions = 1024;
- }//if
+
+ tMaxNoOfTransactions = aMaxNoOfTransactions;
theMaxNoOfTransactions = tMaxNoOfTransactions;
-
+ theRemainingStartTransactions= tMaxNoOfTransactions;
thePreparedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
theSentTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
theCompletedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp
index ccd0cf85c5e..bbc1474f45d 100644
--- a/ndb/src/ndbapi/Ndbinit.cpp
+++ b/ndb/src/ndbapi/Ndbinit.cpp
@@ -59,7 +59,7 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection,
theNoOfPreparedTransactions= 0;
theNoOfSentTransactions= 0;
theNoOfCompletedTransactions= 0;
- theNoOfAllocatedTransactions= 0;
+ theRemainingStartTransactions= 0;
theMaxNoOfTransactions= 0;
theMinNoOfEventsToWakeUp= 0;
theConIdleList= NULL;
diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp
index 6dfd76c160b..96d0f4d7de5 100644
--- a/ndb/src/ndbapi/Ndblist.cpp
+++ b/ndb/src/ndbapi/Ndblist.cpp
@@ -93,7 +93,6 @@ Ndb::createConIdleList(int aNrOfCon)
}
tNdbCon->Status(NdbTransaction::NotConnected);
}
- theNoOfAllocatedTransactions = aNrOfCon;
return aNrOfCon;
}
@@ -193,14 +192,8 @@ Ndb::getNdbCon()
{
NdbTransaction* tNdbCon;
if ( theConIdleList == NULL ) {
- if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) {
- tNdbCon = new NdbTransaction(this);
- if (tNdbCon == NULL) {
- return NULL;
- }//if
- theNoOfAllocatedTransactions++;
- } else {
- ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl;
+ tNdbCon = new NdbTransaction(this);
+ if (tNdbCon == NULL) {
return NULL;
}//if
tNdbCon->next(NULL);
diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp
index e2aa6631841..96f376db5a5 100644
--- a/ndb/src/ndbapi/TransporterFacade.cpp
+++ b/ndb/src/ndbapi/TransporterFacade.cpp
@@ -395,12 +395,10 @@ TransporterFacade::doStop(){
if (theReceiveThread) {
NdbThread_WaitFor(theReceiveThread, &status);
NdbThread_Destroy(&theReceiveThread);
- theReceiveThread= 0;
}
if (theSendThread) {
NdbThread_WaitFor(theSendThread, &status);
NdbThread_Destroy(&theSendThread);
- theSendThread= 0;
}
DBUG_VOID_RETURN;
}
@@ -435,7 +433,7 @@ void TransporterFacade::threadMainSend(void)
theTransporterRegistry->stopSending();
m_socket_server.stopServer();
- m_socket_server.stopSessions();
+ m_socket_server.stopSessions(true);
theTransporterRegistry->stop_clients();
}
@@ -477,6 +475,8 @@ TransporterFacade::TransporterFacade() :
theReceiveThread(NULL),
m_fragmented_signal_id(0)
{
+ DBUG_ENTER("TransporterFacade::TransporterFacade");
+
theOwnId = 0;
theMutexPtr = NdbMutex_Create();
@@ -493,11 +493,15 @@ TransporterFacade::TransporterFacade() :
m_max_trans_id = 0;
theClusterMgr = new ClusterMgr(* this);
+
+ DBUG_VOID_RETURN;
}
bool
TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
{
+ DBUG_ENTER("TransporterFacade::init");
+
theOwnId = nodeId;
theTransporterRegistry = new TransporterRegistry(this);
@@ -506,7 +510,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
* theTransporterRegistry);
if(res <= 0){
TRP_DEBUG( "configureTransporters returned 0 or less" );
- return false;
+ DBUG_RETURN(false);
}
ndb_mgm_configuration_iterator iter(* props, CFG_SECTION_NODE);
@@ -516,7 +520,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
iter.first();
if(iter.find(CFG_NODE_ID, nodeId)){
TRP_DEBUG( "Node info missing from config." );
- return false;
+ DBUG_RETURN(false);
}
Uint32 rank = 0;
@@ -542,7 +546,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
if (!theTransporterRegistry->start_service(m_socket_server)){
ndbout_c("Unable to start theTransporterRegistry->start_service");
- return false;
+ DBUG_RETURN(false);
}
theReceiveThread = NdbThread_Create(runReceiveResponse_C,
@@ -562,7 +566,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
signalLogger.logOn(true, 0, SignalLoggerManager::LogInOut);
#endif
- return true;
+ DBUG_RETURN(true);
}
@@ -683,8 +687,10 @@ TransporterFacade::open(void* objRef,
DBUG_RETURN(r);
}
-TransporterFacade::~TransporterFacade(){
-
+TransporterFacade::~TransporterFacade()
+{
+ DBUG_ENTER("TransporterFacade::~TransporterFacade");
+
NdbMutex_Lock(theMutexPtr);
delete theClusterMgr;
delete theArbitMgr;
@@ -694,6 +700,7 @@ TransporterFacade::~TransporterFacade(){
#ifdef API_TRACE
signalLogger.setOutputStream(0);
#endif
+ DBUG_VOID_RETURN;
}
void
diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp
index 786e8eb1f2e..a88d7d21820 100644
--- a/ndb/test/ndbapi/testBlobs.cpp
+++ b/ndb/test/ndbapi/testBlobs.cpp
@@ -23,14 +23,13 @@
#include <NdbOut.hpp>
#include <NdbTest.hpp>
#include <NdbTick.h>
-#include <ndb/src/ndbapi/NdbBlobImpl.hpp>
struct Bcol {
bool m_nullable;
unsigned m_inline;
unsigned m_partsize;
unsigned m_stripe;
- char m_btname[NdbBlobImpl::BlobTableNameSize];
+ char m_btname[200];
Bcol(bool a, unsigned b, unsigned c, unsigned d) :
m_nullable(a),
m_inline(b),
diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp
index aca8b299b49..dd5846f0d62 100644
--- a/ndb/test/ndbapi/testDict.cpp
+++ b/ndb/test/ndbapi/testDict.cpp
@@ -1009,10 +1009,10 @@ int runGetPrimaryKey(NDBT_Context* ctx, NDBT_Step* step){
struct ErrorCodes { int error_id; bool crash;};
ErrorCodes
NF_codes[] = {
- {6003, true},
- {6004, true},
+ {6003, true}
+ ,{6004, true}
//,6005, true,
- {7173, false}
+ //{7173, false}
};
int
@@ -1031,17 +1031,6 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
- /**
- * Need to run LCP at high rate otherwise
- * packed replicas become "to many"
- */
- int val = DumpStateOrd::DihMinTimeBetweenLCP;
- if(restarter.dumpStateAllNodes(&val, 1) != 0){
- do { CHECK(0); } while(0);
- g_err << "Failed to set LCP to min value" << endl;
- return NDBT_FAILED;
- }
-
const int loops = ctx->getNumLoops();
for (int l = 0; l < loops && result == NDBT_OK ; l++){
const int sz = sizeof(NF_codes)/sizeof(NF_codes[0]);
@@ -1064,7 +1053,7 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){
CHECK2(dict->createTable(* pTab) == 0,
"failed to create table");
-
+
if (crash) {
CHECK2(restarter.waitNodesNoStart(&nodeId, 1) == 0,
"waitNodesNoStart failed");
@@ -1088,9 +1077,6 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){
CHECK2(restarter.waitClusterStarted() == 0,
"waitClusterStarted failed");
}
-
- CHECK2(restarter.dumpStateOneNode(nodeId, &val, 1) == 0,
- "Failed to set LCP to min value");
}
}
}
diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp
index 65324af6fe6..137a1d51d82 100644
--- a/ndb/test/ndbapi/testNdbApi.cpp
+++ b/ndb/test/ndbapi/testNdbApi.cpp
@@ -1269,6 +1269,101 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){
return result;
}
+int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ const Uint32 max= 5;
+ const NdbDictionary::Table* pTab = ctx->getTab();
+
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
+ if (pNdb == NULL){
+ ndbout << "pNdb == NULL" << endl;
+ return NDBT_FAILED;
+ }
+ if (pNdb->init(max)){
+ ERR(pNdb->getNdbError());
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ NdbConnection* pCon = pNdb->startTransaction();
+ if (pCon == NULL){
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ Uint32 i;
+ Vector<NdbScanOperation*> scans;
+ for(i = 0; i<10*max; i++)
+ {
+ NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
+ if (pOp == NULL){
+ ERR(pCon->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+
+ if (pOp->readTuples() != 0){
+ pNdb->closeTransaction(pCon);
+ ERR(pOp->getNdbError());
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+ scans.push_back(pOp);
+ }
+
+ // Dont' call any equal or setValues
+
+ // Execute should not work
+ int check = pCon->execute(NoCommit);
+ if (check == 0){
+ ndbout << "execute worked" << endl;
+ } else {
+ ERR(pCon->getNdbError());
+ }
+
+ for(i= 0; i<scans.size(); i++)
+ {
+ NdbScanOperation* pOp= scans[i];
+ while((check= pOp->nextResult()) == 0);
+ if(check != 1)
+ {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pCon);
+ delete pNdb;
+ return NDBT_FAILED;
+ }
+ }
+
+ pNdb->closeTransaction(pCon);
+
+ Vector<NdbConnection*> cons;
+ for(i= 0; i<10*max; i++)
+ {
+ pCon= pNdb->startTransaction();
+ if(pCon)
+ cons.push_back(pCon);
+ else
+ break;
+ }
+
+ for(i= 0; i<cons.size(); i++)
+ {
+ cons[i]->close();
+ }
+
+ if(cons.size() != max)
+ {
+ result= NDBT_FAILED;
+ }
+
+ delete pNdb;
+
+ return result;
+}
+
+template class Vector<NdbScanOperation*>;
NDBT_TESTSUITE(testNdbApi);
@@ -1351,6 +1446,12 @@ TESTCASE("Bug_11133",
INITIALIZER(runBug_11133);
FINALIZER(runClearTable);
}
+TESTCASE("Scan_4006",
+ "Check that getNdbScanOperation does not get 4006\n"){
+ INITIALIZER(runLoadTable);
+ INITIALIZER(runScan_4006);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNdbApi);
int main(int argc, const char** argv){
diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp
index b6fc2e29bf5..942ee2ec966 100644
--- a/ndb/test/ndbapi/testOIBasic.cpp
+++ b/ndb/test/ndbapi/testOIBasic.cpp
@@ -31,6 +31,7 @@
#include <NdbSleep.h>
#include <my_sys.h>
#include <NdbSqlUtil.hpp>
+#include <ndb_version.h>
// options
@@ -171,6 +172,47 @@ randompct(unsigned pct)
return urandom(100) < pct;
}
+static unsigned
+random_coprime(unsigned n)
+{
+ unsigned prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 };
+ unsigned count = sizeof(prime) / sizeof(prime[0]);
+ if (n == 0)
+ return 0;
+ while (1) {
+ unsigned i = urandom(count);
+ if (n % prime[i] != 0)
+ return prime[i];
+ }
+}
+
+// random re-sequence of 0...(n-1)
+
+struct Rsq {
+ Rsq(unsigned n);
+ unsigned next();
+private:
+ unsigned m_n;
+ unsigned m_i;
+ unsigned m_start;
+ unsigned m_prime;
+};
+
+Rsq::Rsq(unsigned n)
+{
+ m_n = n;
+ m_i = 0;
+ m_start = urandom(n);
+ m_prime = random_coprime(n);
+}
+
+unsigned
+Rsq::next()
+{
+ assert(m_n != 0);
+ return (m_start + m_i++ * m_prime) % m_n;
+}
+
// log and error macros
static NdbMutex *ndbout_mutex = NULL;
@@ -1032,8 +1074,8 @@ makebuiltintables(Par par)
// name - pk - type - length - nullable - cs
t->coladd(0, new Col(*t, 0, "a", 0, Col::Unsigned, 1, 0, 0));
t->coladd(1, new Col(*t, 1, "b", 1, Col::Unsigned, 1, 0, 0));
- t->coladd(2, new Col(*t, 2, "c", 0, Col::Char, 20, 1, getcs(par)));
- t->coladd(3, new Col(*t, 3, "d", 0, Col::Varchar, 5, 0, getcs(par)));
+ t->coladd(2, new Col(*t, 2, "c", 0, Col::Varchar, 20, 0, getcs(par)));
+ t->coladd(3, new Col(*t, 3, "d", 0, Col::Char, 5, 0, getcs(par)));
t->coladd(4, new Col(*t, 4, "e", 0, Col::Longvarchar, 5, 1, getcs(par)));
if (useindex(par, 0)) {
// b
@@ -1071,10 +1113,10 @@ makebuiltintables(Par par)
t->itabadd(4, x);
}
if (useindex(par, 5)) {
- // a, b, d
+ // b, c, d
ITab* x = new ITab(*t, "ti1z5", ITab::UniqueHashIndex, 3);
- x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
- x->icoladd(1, new ICol(*x, 1, *t->m_col[1]));
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
t->itabadd(5, x);
}
@@ -2254,14 +2296,18 @@ Row::insrow(Par par)
assert(! m_exist);
CHK(con.getNdbOperation(tab) == 0);
CHKCON(con.m_op->insertTuple() == 0, con);
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq1.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
}
+ Rsq rsq2(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq2.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (! col.m_pk)
CHK(val.setval(par) == 0);
@@ -2278,14 +2324,18 @@ Row::updrow(Par par)
assert(m_exist);
CHK(con.getNdbOperation(tab) == 0);
CHKCON(con.m_op->updateTuple() == 0, con);
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq1.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
}
+ Rsq rsq2(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq2.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (! col.m_pk)
CHK(val.setval(par) == 0);
@@ -2303,15 +2353,19 @@ Row::updrow(Par par, const ITab& itab)
assert(m_exist);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
CHKCON(con.m_op->updateTuple() == 0, con);
+ Rsq rsq1(itab.m_icols);
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = *itab.m_icol[k];
+ unsigned k2 = rsq1.next();
+ const ICol& icol = *itab.m_icol[k2];
const Col& col = icol.m_col;
unsigned m = col.m_num;
const Val& val = *m_val[m];
CHK(val.equal(par, icol) == 0);
}
+ Rsq rsq2(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq2.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (! col.m_pk)
CHK(val.setval(par) == 0);
@@ -2328,8 +2382,10 @@ Row::delrow(Par par)
assert(m_exist);
CHK(con.getNdbOperation(m_tab) == 0);
CHKCON(con.m_op->deleteTuple() == 0, con);
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq1.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
@@ -2347,8 +2403,10 @@ Row::delrow(Par par, const ITab& itab)
assert(m_exist);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
CHKCON(con.m_op->deleteTuple() == 0, con);
+ Rsq rsq1(itab.m_icols);
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = *itab.m_icol[k];
+ unsigned k2 = rsq1.next();
+ const ICol& icol = *itab.m_icol[k2];
const Col& col = icol.m_col;
unsigned m = col.m_num;
const Val& val = *m_val[m];
@@ -2365,8 +2423,10 @@ Row::selrow(Par par)
const Tab& tab = m_tab;
CHK(con.getNdbOperation(m_tab) == 0);
CHKCON(con.m_op->readTuple() == 0, con);
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq1.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
@@ -2382,8 +2442,10 @@ Row::selrow(Par par, const ITab& itab)
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
CHKCON(con.m_op->readTuple() == 0, con);
+ Rsq rsq1(itab.m_icols);
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = *itab.m_icol[k];
+ unsigned k2 = rsq1.next();
+ const ICol& icol = *itab.m_icol[k2];
const Col& col = icol.m_col;
unsigned m = col.m_num;
const Val& val = *m_val[m];
@@ -2397,8 +2459,10 @@ Row::setrow(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ unsigned k2 = rsq1.next();
+ const Val& val = *m_val[k2];
const Col& col = val.m_col;
if (! col.m_pk)
CHK(val.setval(par) == 0);
@@ -2810,8 +2874,10 @@ Set::getval(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
+ Rsq rsq1(tab.m_cols);
for (unsigned k = 0; k < tab.m_cols; k++) {
- CHK(con.getValue(k, m_rec[k]) == 0);
+ unsigned k2 = rsq1.next();
+ CHK(con.getValue(k2, m_rec[k2]) == 0);
}
return 0;
}
@@ -3093,18 +3159,16 @@ int
BSet::setbnd(Par par) const
{
if (m_bvals != 0) {
- unsigned p1 = urandom(m_bvals);
- unsigned p2 = 10009; // prime
- // random order
+ Rsq rsq1(m_bvals);
for (unsigned j = 0; j < m_bvals; j++) {
- unsigned k = p1 + p2 * j;
- const BVal& bval = *m_bval[k % m_bvals];
+ unsigned j2 = rsq1.next();
+ const BVal& bval = *m_bval[j2];
CHK(bval.setbnd(par) == 0);
}
// duplicate
if (urandom(5) == 0) {
- unsigned k = urandom(m_bvals);
- const BVal& bval = *m_bval[k];
+ unsigned j3 = urandom(m_bvals);
+ const BVal& bval = *m_bval[j3];
CHK(bval.setbnd(par) == 0);
}
}
@@ -3118,19 +3182,16 @@ BSet::setflt(Par par) const
CHK(con.getNdbScanFilter() == 0);
CHK(con.beginFilter(NdbScanFilter::AND) == 0);
if (m_bvals != 0) {
- unsigned p1 = urandom(m_bvals);
- unsigned p2 = 10009; // prime
- const unsigned extras = 5;
- // random order
- for (unsigned j = 0; j < m_bvals + extras; j++) {
- unsigned k = p1 + p2 * j;
- const BVal& bval = *m_bval[k % m_bvals];
+ Rsq rsq1(m_bvals);
+ for (unsigned j = 0; j < m_bvals; j++) {
+ unsigned j2 = rsq1.next();
+ const BVal& bval = *m_bval[j2];
CHK(bval.setflt(par) == 0);
}
// duplicate
if (urandom(5) == 0) {
- unsigned k = urandom(m_bvals);
- const BVal& bval = *m_bval[k];
+ unsigned j3 = urandom(m_bvals);
+ const BVal& bval = *m_bval[j3];
CHK(bval.setflt(par) == 0);
}
}
@@ -4176,7 +4237,8 @@ readverifyfull(Par par)
CHK(scanreadtable(par) == 0);
// once more via tup scan
par.m_tupscan = true;
- CHK(scanreadtable(par) == 0);
+ if (NDB_VERSION < MAKE_VERSION(5, 1, 0)) //TODO
+ CHK(scanreadtable(par) == 0);
}
// each thread scans different indexes
for (unsigned i = 0; i < tab.m_itabs; i++) {
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index ce9f97a9cb2..5d7d7f58f89 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -520,6 +520,10 @@ max-time: 500
cmd: testNdbApi
args: -n Bug_11133 T1
+max-time: 500
+cmd: testNdbApi
+args: -n Scan_4006 T1
+
#max-time: 500
#cmd: testInterpreter
#args: T1
diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp
index 93c40d31adb..d980f29057b 100644
--- a/ndb/tools/restore/restore_main.cpp
+++ b/ndb/tools/restore/restore_main.cpp
@@ -255,8 +255,9 @@ main(int argc, char** argv)
const BackupFormat::FileHeader & tmp = metaData.getFileHeader();
const Uint32 version = tmp.NdbVersion;
+ char buf[NDB_VERSION_STRING_BUF_SZ];
ndbout << "Ndb version in backup files: "
- << getVersionString(version, 0) << endl;
+ << getVersionString(version, 0, buf, sizeof(buf)) << endl;
/**
* check wheater we can restore the backup (right version).
diff --git a/netware/Makefile.am b/netware/Makefile.am
index 92c8afba896..be59efd1deb 100644
--- a/netware/Makefile.am
+++ b/netware/Makefile.am
@@ -15,7 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
if HAVE_NETWARE
-INCLUDES = -I$(srcdir)/../include -I../include -I..
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I..
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
bin_PROGRAMS = mysqld_safe mysql_install_db mysql_test_run libmysql
diff --git a/netware/my_print_defaults.def b/netware/my_print_defaults.def
index 826981256b5..d88c5adf4cc 100644
--- a/netware/my_print_defaults.def
+++ b/netware/my_print_defaults.def
@@ -4,7 +4,8 @@
MODULE libc.nlm
COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved."
DESCRIPTION "MySQL Print Defaults Tool"
-VERSION 4, 0
+VERSION 5, 0, 8
+STACKSIZE 32767
XDCDATA ../netware/mysql.xdc
#DEBUG
diff --git a/regex/Makefile.am b/regex/Makefile.am
index 07d7a03635d..3b161287d36 100644
--- a/regex/Makefile.am
+++ b/regex/Makefile.am
@@ -15,7 +15,7 @@
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
noinst_LIBRARIES = libregex.a
LDADD= libregex.a $(top_builddir)/strings/libmystrings.a
noinst_HEADERS = cclass.h cname.h regex2.h utils.h engine.c regex.h
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 74734f4dd5f..fbdbd998138 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -27,7 +27,7 @@ parse_arguments() {
--tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;;
--suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;;
--no-strip) STRIP=0 ;;
- --machine) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;;
+ --machine=*) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;;
--silent) SILENT=1 ;;
--with-ndbcluster) NDBCLUSTER=1 ;;
*)
@@ -221,6 +221,7 @@ done
$CP mysql-test/lib/*.pl $BASE/mysql-test/lib
$CP mysql-test/lib/*.sql $BASE/mysql-test/lib
$CP mysql-test/include/*.inc $BASE/mysql-test/include
+$CP mysql-test/t/*.def $BASE/mysql-test/t
$CP mysql-test/std_data/*.dat mysql-test/std_data/*.frm \
mysql-test/std_data/*.pem mysql-test/std_data/Moscow_leap \
mysql-test/std_data/des_key_file mysql-test/std_data/*.*001 \
diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh
index 6165a31fac2..c79433f97c1 100644
--- a/scripts/make_win_src_distribution.sh
+++ b/scripts/make_win_src_distribution.sh
@@ -361,6 +361,9 @@ if [ -d $BASE/SSL/SCCS ]
then
find $BASE/ -type d -name SCCS -printf " \"%p\"" | xargs rm -r -f
fi
+find $BASE/ -type d -name .deps -printf " \"%p\"" | xargs rm -r -f
+find $BASE/ -type d -name .libs -printf " \"%p\"" | xargs rm -r -f
+rm -r -f "$BASE/mysql-test/var"
#
# Initialize the initial data directory
diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh
index a5c8af5ecb2..16e50c044ca 100644
--- a/scripts/mysql_config.sh
+++ b/scripts/mysql_config.sh
@@ -60,11 +60,19 @@ fix_path ()
get_full_path ()
{
- case $1 in
- /*) echo "$1";;
- ./*) tmp=`pwd`/$1; echo $tmp | sed -e 's;/\./;/;' ;;
- *) which $1 ;;
- esac
+ file=$1
+
+ # if the file is a symlink, try to resolve it
+ if [ -h $file ];
+ then
+ file=`ls -l $file | awk '{ print $NF }'`
+ fi
+
+ case $file in
+ /*) echo "$file";;
+ */*) tmp=`pwd`/$file; echo $tmp | sed -e 's;/\./;/;' ;;
+ *) which $file ;;
+ esac
}
me=`get_full_path $0`
diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh
index a8f6c02b057..a3036b5c10b 100644
--- a/scripts/mysql_create_system_tables.sh
+++ b/scripts/mysql_create_system_tables.sh
@@ -215,7 +215,7 @@ then
c_t="$c_t Table_name char(64) binary DEFAULT '' NOT NULL,"
c_t="$c_t Grantor char(77) DEFAULT '' NOT NULL,"
c_t="$c_t Timestamp timestamp(14),"
- c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
+ c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
c_t="$c_t Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
c_t="$c_t PRIMARY KEY (Host,Db,User,Table_name),"
c_t="$c_t KEY Grantor (Grantor)"
@@ -669,7 +669,7 @@ fi
if test ! -f $mdata/proc.frm
then
c_p="$c_p CREATE TABLE proc ("
- c_p="$c_p db char(64) binary DEFAULT '' NOT NULL,"
+ c_p="$c_p db char(64) collate utf8_bin DEFAULT '' NOT NULL,"
c_p="$c_p name char(64) DEFAULT '' NOT NULL,"
c_p="$c_p type enum('FUNCTION','PROCEDURE') NOT NULL,"
c_p="$c_p specific_name char(64) DEFAULT '' NOT NULL,"
@@ -684,7 +684,7 @@ then
c_p="$c_p param_list blob DEFAULT '' NOT NULL,"
c_p="$c_p returns char(64) DEFAULT '' NOT NULL,"
c_p="$c_p body blob DEFAULT '' NOT NULL,"
- c_p="$c_p definer char(77) binary DEFAULT '' NOT NULL,"
+ c_p="$c_p definer char(77) collate utf8_bin DEFAULT '' NOT NULL,"
c_p="$c_p created timestamp,"
c_p="$c_p modified timestamp,"
c_p="$c_p sql_mode set("
@@ -718,10 +718,12 @@ then
c_p="$c_p 'TRADITIONAL',"
c_p="$c_p 'NO_AUTO_CREATE_USER',"
c_p="$c_p 'HIGH_NOT_PRECEDENCE'"
- c_p="$c_p ) DEFAULT 0 NOT NULL,"
- c_p="$c_p comment char(64) binary DEFAULT '' NOT NULL,"
+ c_p="$c_p ) DEFAULT '' NOT NULL,"
+ c_p="$c_p comment char(64) collate utf8_bin DEFAULT '' NOT NULL,"
c_p="$c_p PRIMARY KEY (db,name,type)"
- c_p="$c_p ) comment='Stored Procedures';"
+ c_p="$c_p ) engine=MyISAM"
+ c_p="$c_p character set utf8"
+ c_p="$c_p comment='Stored Procedures';"
fi
cat << END_OF_DATA
diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql
index 68b31cf1519..b93e0a47b1b 100644
--- a/scripts/mysql_fix_privilege_tables.sql
+++ b/scripts/mysql_fix_privilege_tables.sql
@@ -261,6 +261,11 @@ ALTER TABLE host ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAUL
ALTER TABLE user ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv;
#
+# Show/Create views table privileges (v5.0)
+#
+ALTER TABLE tables_priv MODIFY Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL;
+
+#
# Assign create/show view privileges to people who have create provileges
#
UPDATE user SET Create_view_priv=Create_priv, Show_view_priv=Create_priv where user<>"" AND @hadCreateViewPriv = 0;
@@ -407,22 +412,22 @@ PRIMARY KEY TranTime (Transition_time)
#
CREATE TABLE IF NOT EXISTS proc (
- db char(64) binary DEFAULT '' NOT NULL,
+ db char(64) collate utf8_bin DEFAULT '' NOT NULL,
name char(64) DEFAULT '' NOT NULL,
type enum('FUNCTION','PROCEDURE') NOT NULL,
specific_name char(64) DEFAULT '' NOT NULL,
language enum('SQL') DEFAULT 'SQL' NOT NULL,
sql_data_access enum('CONTAINS_SQL',
- 'NO_SQL',
- 'READS_SQL_DATA',
- 'MODIFIES_SQL_DATA'
- ) DEFAULT 'CONTAINS_SQL' NOT NULL,
+ 'NO_SQL',
+ 'READS_SQL_DATA',
+ 'MODIFIES_SQL_DATA'
+ ) DEFAULT 'CONTAINS_SQL' NOT NULL,
is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,
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,
- definer char(77) binary DEFAULT '' NOT NULL,
+ definer char(77) collate utf8_bin DEFAULT '' NOT NULL,
created timestamp,
modified timestamp,
sql_mode set(
@@ -456,20 +461,22 @@ CREATE TABLE IF NOT EXISTS proc (
'TRADITIONAL',
'NO_AUTO_CREATE_USER',
'HIGH_NOT_PRECEDENCE'
- ) DEFAULT 0 NOT NULL,
- comment char(64) binary DEFAULT '' NOT NULL,
+ ) DEFAULT '' NOT NULL,
+ comment char(64) collate utf8_bin DEFAULT '' NOT NULL,
PRIMARY KEY (db,name,type)
-) comment='Stored Procedures';
+) engine=MyISAM
+ character set utf8
+ comment='Stored Procedures';
# Correct the name fields to not binary, and expand sql_data_access
ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL,
MODIFY specific_name char(64) DEFAULT '' NOT NULL,
- MODIFY sql_data_access
- enum('CONTAINS_SQL',
- 'NO_SQL',
- 'READS_SQL_DATA',
- 'MODIFIES_SQL_DATA'
- ) DEFAULT 'CONTAINS_SQL' NOT NULL,
+ MODIFY sql_data_access
+ enum('CONTAINS_SQL',
+ 'NO_SQL',
+ 'READS_SQL_DATA',
+ 'MODIFIES_SQL_DATA'
+ ) DEFAULT 'CONTAINS_SQL' NOT NULL,
MODIFY sql_mode
set('REAL_AS_FLOAT',
'PIPES_AS_CONCAT',
@@ -501,4 +508,15 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL,
'TRADITIONAL',
'NO_AUTO_CREATE_USER',
'HIGH_NOT_PRECEDENCE'
- ) DEFAULT 0 NOT NULL;
+ ) DEFAULT '' NOT NULL
+ DEFAULT CHARACTER SET utf8;
+
+# Correct the character set and collation
+ALTER TABLE proc CONVERT TO CHARACTER SET utf8;
+# Reset some fields after the conversion
+ALTER TABLE proc MODIFY db
+ char(64) collate utf8_bin DEFAULT '' NOT NULL,
+ MODIFY definer
+ char(77) collate utf8_bin DEFAULT '' NOT NULL,
+ MODIFY comment
+ char(64) collate utf8_bin DEFAULT '' NOT NULL;
diff --git a/sql-common/client.c b/sql-common/client.c
index c736acae857..4ecc8d26fc7 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -2206,7 +2206,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
tmp_mysql.rpl_pivot = mysql->rpl_pivot;
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
- mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
+ mysql->client_flag | CLIENT_REMEMBER_OPTIONS) ||
+ mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
{
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
@@ -2778,8 +2779,49 @@ uint STDCALL mysql_errno(MYSQL *mysql)
return mysql->net.last_errno;
}
+
const char * STDCALL mysql_error(MYSQL *mysql)
{
return mysql->net.last_error;
}
+/*
+ mysql_set_character_set function sends SET NAMES cs_name to
+ the server (which changes character_set_client, character_set_result
+ and character_set_connection) and updates mysql->charset so other
+ functions like mysql_real_escape will work correctly.
+*/
+int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
+{
+ struct charset_info_st *cs;
+ const char *save_csdir= charsets_dir;
+
+ if (mysql->options.charset_dir)
+ charsets_dir= mysql->options.charset_dir;
+
+ if (strlen(cs_name) < MY_CS_NAME_SIZE &&
+ (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
+ {
+ char buff[MY_CS_NAME_SIZE + 10];
+ charsets_dir= save_csdir;
+ sprintf(buff, "SET NAMES %s", cs_name);
+ if (!mysql_real_query(mysql, buff, strlen(buff)))
+ {
+ mysql->charset= cs;
+ }
+ }
+ else
+ {
+ char cs_dir_name[FN_REFLEN];
+ get_charsets_dir(cs_dir_name);
+ mysql->net.last_errno= CR_CANT_READ_CHARSET;
+ strmov(mysql->net.sqlstate, unknown_sqlstate);
+ my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
+ ER(mysql->net.last_errno), cs_name, cs_dir_name);
+
+ }
+ charsets_dir= save_csdir;
+ return mysql->net.last_errno;
+}
+
+
diff --git a/sql/Makefile.am b/sql/Makefile.am
index b506d2a767b..cabb4fee905 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -21,8 +21,8 @@ MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
INCLUDES = @ZLIB_INCLUDES@ \
@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
- -I$(top_srcdir)/include -I$(top_srcdir)/regex \
- -I$(srcdir) $(openssl_includes) -I$(top_builddir)/include
+ -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
@@ -111,8 +111,8 @@ DEFS = -DMYSQL_SERVER \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
@DEFS@
-# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
-BUILT_SOURCES = sql_yacc.cc sql_yacc.h
+
+BUILT_SOURCES = sql_yacc.cc sql_yacc.h lex_hash.h
EXTRA_DIST = udf_example.cc $(BUILT_SOURCES)
DISTCLEANFILES = lex_hash.h
AM_YFLAGS = -d
@@ -131,9 +131,6 @@ link_sources: mysql_tzinfo_to_sql.cc
rm -f my_time.c
@LN_CP_F@ ../sql-common/my_time.c my_time.c
-gen_lex_hash.o: gen_lex_hash.cc lex.h
- $(CXXCOMPILE) -c $(INCLUDES) $<
-
mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES)
$(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $<
@@ -148,13 +145,9 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS)
@echo "If it fails, re-run configure with --with-low-memory"
$(CXXCOMPILE) $(LM_CFLAGS) -c $<
-lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h
- $(MAKE) gen_lex_hash$(EXEEXT)
+lex_hash.h: gen_lex_hash$(EXEEXT)
./gen_lex_hash$(EXEEXT) > $@
-# Hack to ensure that lex_hash.h is built early
-sql_lex.o: lex_hash.h
-
# For testing of udf_example.so; Works on platforms with gcc
# (This is not part of our build process but only provided as an example)
udf_example.so: udf_example.cc
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index a5a3e78d70f..34bcbd4fc4b 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -22,7 +22,17 @@
struct st_des_keyschedule des_keyschedule[10];
uint des_default_key;
pthread_mutex_t LOCK_des_key_file;
-static int initialized;
+static int initialized= 0;
+
+void
+init_des_key_file()
+{
+ if (!initialized)
+ {
+ initialized=1;
+ pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+ }
+}
/*
Function which loads DES keys from plaintext file into memory on MySQL
@@ -45,11 +55,7 @@ load_des_key_file(const char *file_name)
DBUG_ENTER("load_des_key_file");
DBUG_PRINT("enter",("name: %s",file_name));
- if (!initialized)
- {
- initialized=1;
- pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
- }
+ init_des_key_file();
VOID(pthread_mutex_lock(&LOCK_des_key_file));
if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index 93cedcbf251..c362985f565 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -259,7 +259,7 @@ error:
This method reads the header of a meta file and returns whether or not it was successful.
*rows will contain the current number of rows in the data file upon success.
*/
-int ha_archive::read_meta_file(File meta_file, ulonglong *rows)
+int ha_archive::read_meta_file(File meta_file, ha_rows *rows)
{
uchar meta_buffer[META_BUFFER_SIZE];
ulonglong check_point;
@@ -273,7 +273,7 @@ int ha_archive::read_meta_file(File meta_file, ulonglong *rows)
/*
Parse out the meta data, we ignore version at the moment
*/
- *rows= uint8korr(meta_buffer + 2);
+ *rows= (ha_rows)uint8korr(meta_buffer + 2);
check_point= uint8korr(meta_buffer + 10);
DBUG_PRINT("ha_archive::read_meta_file", ("Check %d", (uint)meta_buffer[0]));
@@ -296,7 +296,7 @@ int ha_archive::read_meta_file(File meta_file, ulonglong *rows)
By setting dirty you say whether or not the file represents the actual state of the data file.
Upon ::open() we set to dirty, and upon ::close() we set to clean.
*/
-int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty)
+int ha_archive::write_meta_file(File meta_file, ha_rows rows, bool dirty)
{
uchar meta_buffer[META_BUFFER_SIZE];
ulonglong check_point= 0; //Reserved for the future
@@ -305,12 +305,12 @@ int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty)
meta_buffer[0]= (uchar)ARCHIVE_CHECK_HEADER;
meta_buffer[1]= (uchar)ARCHIVE_VERSION;
- int8store(meta_buffer + 2, rows);
+ int8store(meta_buffer + 2, (ulonglong)rows);
int8store(meta_buffer + 10, check_point);
*(meta_buffer + 18)= (uchar)dirty;
DBUG_PRINT("ha_archive::write_meta_file", ("Check %d", (uint)ARCHIVE_CHECK_HEADER));
DBUG_PRINT("ha_archive::write_meta_file", ("Version %d", (uint)ARCHIVE_VERSION));
- DBUG_PRINT("ha_archive::write_meta_file", ("Rows %llu", rows));
+ DBUG_PRINT("ha_archive::write_meta_file", ("Rows %llu", (ulonglong)rows));
DBUG_PRINT("ha_archive::write_meta_file", ("Checkpoint %llu", check_point));
DBUG_PRINT("ha_archive::write_meta_file", ("Dirty %d", (uint)dirty));
@@ -326,6 +326,9 @@ int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty)
/*
We create the shared memory space that we will use for the open table.
+ No matter what we try to get or create a share. This is so that a repair
+ table operation can occur.
+
See ha_example.cc for a longer description.
*/
ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
@@ -363,7 +366,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
*/
VOID(pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST));
if ((share->meta_file= my_open(meta_file_name, O_RDWR, MYF(0))) == -1)
- goto error;
+ share->crashed= TRUE;
/*
After we read, we set the file to dirty. When we close, we will do the
@@ -381,27 +384,14 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
that is shared amoung all open tables.
*/
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
- goto error2;
- if (my_hash_insert(&archive_open_tables, (byte*) share))
- goto error3;
+ share->crashed= TRUE;
+ VOID(my_hash_insert(&archive_open_tables, (byte*) share));
thr_lock_init(&share->lock);
}
share->use_count++;
pthread_mutex_unlock(&archive_mutex);
return share;
-
-error3:
- /* We close, but ignore errors since we already have errors */
- (void)gzclose(share->archive_write);
-error2:
- my_close(share->meta_file,MYF(0));
-error:
- pthread_mutex_unlock(&archive_mutex);
- VOID(pthread_mutex_destroy(&share->mutex));
- my_free((gptr) share, MYF(0));
-
- return NULL;
}
@@ -458,13 +448,14 @@ int ha_archive::open(const char *name, int mode, uint test_if_locked)
DBUG_ENTER("ha_archive::open");
if (!(share= get_share(name, table)))
- DBUG_RETURN(-1);
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM); // Not handled well by calling code!
thr_lock_data_init(&share->lock,&lock,NULL);
if ((archive= gzopen(share->data_file_name, "rb")) == NULL)
{
- (void)free_share(share); //We void since we already have an error
- DBUG_RETURN(errno ? errno : -1);
+ if (errno == EROFS || errno == EACCES)
+ DBUG_RETURN(my_errno= errno);
+ DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
DBUG_RETURN(0);
@@ -572,36 +563,22 @@ error:
DBUG_RETURN(error ? error : -1);
}
-
-/*
- Look at ha_archive::open() for an explanation of the row format.
- Here we just write out the row.
-
- Wondering about start_bulk_insert()? We don't implement it for
- archive since it optimizes for lots of writes. The only save
- for implementing start_bulk_insert() is that we could skip
- setting dirty to true each time.
+/*
+ This is where the actual row is written out.
*/
-int ha_archive::write_row(byte * buf)
+int ha_archive::real_write_row(byte *buf, gzFile writer)
{
z_off_t written;
uint *ptr, *end;
- DBUG_ENTER("ha_archive::write_row");
+ DBUG_ENTER("ha_archive::real_write_row");
- if (share->crashed)
- DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
-
- statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
- pthread_mutex_lock(&share->mutex);
- written= gzwrite(share->archive_write, buf, table->s->reclength);
- DBUG_PRINT("ha_archive::write_row", ("Wrote %d bytes expected %d", written, table->s->reclength));
+ written= gzwrite(writer, buf, table->s->reclength);
+ DBUG_PRINT("ha_archive::real_write_row", ("Wrote %d bytes expected %d", written, table->s->reclength));
if (!delayed_insert || !bulk_insert)
share->dirty= TRUE;
if (written != (z_off_t)table->s->reclength)
- goto error;
+ DBUG_RETURN(errno ? errno : -1);
/*
We should probably mark the table as damagaged if the record is written
but the blob fails.
@@ -616,21 +593,43 @@ int ha_archive::write_row(byte * buf)
if (size)
{
((Field_blob*) table->field[*ptr])->get_ptr(&data_ptr);
- written= gzwrite(share->archive_write, data_ptr, (unsigned)size);
+ written= gzwrite(writer, data_ptr, (unsigned)size);
if (written != (z_off_t)size)
- goto error;
+ DBUG_RETURN(errno ? errno : -1);
}
}
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Look at ha_archive::open() for an explanation of the row format.
+ Here we just write out the row.
+
+ Wondering about start_bulk_insert()? We don't implement it for
+ archive since it optimizes for lots of writes. The only save
+ for implementing start_bulk_insert() is that we could skip
+ setting dirty to true each time.
+*/
+int ha_archive::write_row(byte *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_archive::write_row");
+
+ if (share->crashed)
+ DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+ statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
+ table->timestamp_field->set_time();
+ pthread_mutex_lock(&share->mutex);
share->rows_recorded++;
+ rc= real_write_row(buf, share->archive_write);
pthread_mutex_unlock(&share->mutex);
- DBUG_RETURN(0);
-error:
- pthread_mutex_unlock(&share->mutex);
- DBUG_RETURN(errno ? errno : -1);
+ DBUG_RETURN(rc);
}
-
/*
All calls that need to scan the table start with this method. If we are told
that it is a table scan we rewind the file to the beginning, otherwise
@@ -787,7 +786,7 @@ int ha_archive::rnd_pos(byte * buf, byte *pos)
DBUG_ENTER("ha_archive::rnd_pos");
statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
&LOCK_status);
- current_position= my_get_ptr(pos, ref_length);
+ current_position= (z_off_t)my_get_ptr(pos, ref_length);
(void)gzseek(archive, current_position, SEEK_SET);
DBUG_RETURN(get_row(archive, buf));
@@ -795,68 +794,20 @@ int ha_archive::rnd_pos(byte * buf, byte *pos)
/*
This method repairs the meta file. It does this by walking the datafile and
- rewriting the meta file.
+ rewriting the meta file. Currently it does this by calling optimize with
+ the extended flag.
*/
int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt)
{
- int rc;
- byte *buf;
- ulonglong rows_recorded= 0;
- gzFile rebuild_file; // Archive file we are working with
- File meta_file; // Meta file we use
- char data_file_name[FN_REFLEN];
DBUG_ENTER("ha_archive::repair");
+ check_opt->flags= T_EXTEND;
+ int rc= optimize(thd, check_opt);
- /*
- Open up the meta file to recreate it.
- */
- fn_format(data_file_name, share->table_name, "", ARZ,
- MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- if ((rebuild_file= gzopen(data_file_name, "rb")) == NULL)
- DBUG_RETURN(errno ? errno : -1);
+ if (rc)
+ DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR);
- if ((rc= read_data_header(rebuild_file)))
- goto error;
-
- /*
- We malloc up the buffer we will use for counting the rows.
- I know, this malloc'ing memory but this should be a very
- rare event.
- */
- if (!(buf= (byte*) my_malloc(table->s->rec_buff_length > sizeof(ulonglong) +1 ?
- table->s->rec_buff_length : sizeof(ulonglong) +1 ,
- MYF(MY_WME))))
- {
- rc= HA_ERR_CRASHED_ON_USAGE;
- goto error;
- }
-
- while (!(rc= get_row(rebuild_file, buf)))
- rows_recorded++;
-
- /*
- Only if we reach the end of the file do we assume we can rewrite.
- At this point we reset rc to a non-message state.
- */
- if (rc == HA_ERR_END_OF_FILE)
- {
- fn_format(data_file_name,share->table_name,"",ARM,MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- if ((meta_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1)
- {
- rc= HA_ERR_CRASHED_ON_USAGE;
- goto error;
- }
- (void)write_meta_file(meta_file, rows_recorded, TRUE);
- my_close(meta_file,MYF(0));
- rc= 0;
- }
-
- my_free((gptr) buf, MYF(0));
share->crashed= FALSE;
-error:
- gzclose(rebuild_file);
-
- DBUG_RETURN(rc);
+ DBUG_RETURN(0);
}
/*
@@ -866,39 +817,100 @@ error:
int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("ha_archive::optimize");
- int read; // Bytes read, gzread() returns int
- gzFile reader, writer;
- char block[IO_SIZE];
+ int rc;
+ gzFile writer;
char writer_filename[FN_REFLEN];
- /* Closing will cause all data waiting to be flushed */
- gzclose(share->archive_write);
- share->archive_write= NULL;
+ /* Flush any waiting data */
+ gzflush(share->archive_write, Z_SYNC_FLUSH);
/* Lets create a file to contain the new data */
fn_format(writer_filename, share->table_name, "", ARN,
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- if ((reader= gzopen(share->data_file_name, "rb")) == NULL)
- DBUG_RETURN(-1);
-
if ((writer= gzopen(writer_filename, "wb")) == NULL)
+ DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+ /*
+ An extended rebuild is a lot more effort. We open up each row and re-record it.
+ Any dead rows are removed (aka rows that may have been partially recorded).
+ */
+
+ if (check_opt->flags == T_EXTEND)
{
- gzclose(reader);
- DBUG_RETURN(-1);
- }
+ byte *buf;
- while ((read= gzread(reader, block, IO_SIZE)))
- gzwrite(writer, block, read);
+ /*
+ First we create a buffer that we can use for reading rows, and can pass
+ to get_row().
+ */
+ if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
+ {
+ rc= HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
- gzclose(reader);
- gzclose(writer);
+ /*
+ Now we will rewind the archive file so that we are positioned at the
+ start of the file.
+ */
+ rc= read_data_header(archive);
+
+ /*
+ Assuming now error from rewinding the archive file, we now write out the
+ new header for out data file.
+ */
+ if (!rc)
+ rc= write_data_header(writer);
+
+ /*
+ On success of writing out the new header, we now fetch each row and
+ insert it into the new archive file.
+ */
+ if (!rc)
+ {
+ share->rows_recorded= 0;
+ while (!(rc= get_row(archive, buf)))
+ {
+ real_write_row(buf, writer);
+ share->rows_recorded++;
+ }
+ }
+
+ my_free((char*)buf, MYF(0));
+ if (rc && rc != HA_ERR_END_OF_FILE)
+ goto error;
+ }
+ else
+ {
+ /*
+ The quick method is to just read the data raw, and then compress it directly.
+ */
+ int read; // Bytes read, gzread() returns int
+ char block[IO_SIZE];
+ if (gzrewind(archive) == -1)
+ {
+ rc= HA_ERR_CRASHED_ON_USAGE;
+ goto error;
+ }
+
+ while ((read= gzread(archive, block, IO_SIZE)))
+ gzwrite(writer, block, read);
+ }
+
+ gzflush(writer, Z_SYNC_FLUSH);
+ gzclose(share->archive_write);
+ share->archive_write= writer;
my_rename(writer_filename,share->data_file_name,MYF(0));
DBUG_RETURN(0);
-}
+error:
+ gzclose(writer);
+
+ DBUG_RETURN(rc);
+}
/*
Below is an example of how to setup row level locking.
diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h
index 2f310d8c69b..3932b62980c 100644
--- a/sql/examples/ha_archive.h
+++ b/sql/examples/ha_archive.h
@@ -36,7 +36,7 @@ typedef struct st_archive_share {
gzFile archive_write; /* Archive file we are working with */
bool dirty; /* Flag for if a flush should occur */
bool crashed; /* Meta file is crashed */
- ulonglong rows_recorded; /* Number of rows in tables */
+ ha_rows rows_recorded; /* Number of rows in tables */
} ARCHIVE_SHARE;
/*
@@ -53,7 +53,7 @@ class ha_archive: public handler
z_off_t current_position; /* The position of the row we just read */
byte byte_buffer[IO_SIZE]; /* Initial buffer for our string */
String buffer; /* Buffer used for blob storage */
- ulonglong scan_rows; /* Number of rows left in scan */
+ ha_rows scan_rows; /* Number of rows left in scan */
bool delayed_insert; /* If the insert is delayed */
bool bulk_insert; /* If we are performing a bulk insert */
@@ -84,12 +84,13 @@ public:
int open(const char *name, int mode, uint test_if_locked);
int close(void);
int write_row(byte * buf);
+ int real_write_row(byte *buf, gzFile writer);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
int get_row(gzFile file_to_read, byte *buf);
- int read_meta_file(File meta_file, ulonglong *rows);
- int write_meta_file(File meta_file, ulonglong rows, bool dirty);
+ int read_meta_file(File meta_file, ha_rows *rows);
+ int write_meta_file(File meta_file, ha_rows rows, bool dirty);
ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table);
int free_share(ARCHIVE_SHARE *share);
bool auto_repair() const { return 1; } // For the moment we just do this
@@ -102,6 +103,10 @@ public:
int repair(THD* thd, HA_CHECK_OPT* check_opt);
void start_bulk_insert(ha_rows rows);
int end_bulk_insert();
+ enum row_type get_row_type() const
+ {
+ return ROW_TYPE_COMPRESSED;
+ }
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
};
diff --git a/sql/field.cc b/sql/field.cc
index 6e63dad41bb..52f260e7b2d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -38,7 +38,7 @@
Instansiate templates and static variables
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<create_field>;
template class List_iterator<create_field>;
#endif
@@ -47,6 +47,8 @@ uchar Field_null::null[1]={1};
const char field_separator=',';
#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320
+#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
+((ulong) ((LL(1) << min(arg, 4) * 8) - LL(1)))
/*
Rules for merging different types of fields in UNION
@@ -1444,6 +1446,7 @@ my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
uint Field::fill_cache_field(CACHE_FIELD *copy)
{
+ uint store_length;
copy->str=ptr;
copy->length=pack_length();
copy->blob_field=0;
@@ -1457,10 +1460,16 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
else if (!zero_pack() &&
(type() == MYSQL_TYPE_STRING && copy->length >= 4 &&
copy->length < 256))
+ {
copy->strip=1; /* Remove end space */
+ store_length= 2;
+ }
else
+ {
copy->strip=0;
- return copy->length+(int) copy->strip;
+ store_length= 0;
+ }
+ return copy->length+ store_length;
}
@@ -2479,7 +2488,7 @@ int Field_new_decimal::store(longlong nr)
int err;
if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
- nr, false, &decimal_value)))
+ nr, FALSE, &decimal_value)))
{
if (check_overflow(err))
set_value_on_overflow(&decimal_value, decimal_value.sign());
@@ -3317,12 +3326,12 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
}
if (error)
{
- error= 1;
+ error= error != MY_ERRNO_EDOM ? 1 : 2;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
}
else if (from+len != end && table->in_use->count_cuted_fields &&
check_int(from,len,end,cs))
- error= 1;
+ error= 2;
store_tmp= (long) tmp;
#ifdef WORDS_BIGENDIAN
@@ -3584,7 +3593,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
}
else if (from+len != end && table->in_use->count_cuted_fields &&
check_int(from,len,end,cs))
- error= 1;
+ error= 2;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
@@ -3806,7 +3815,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
- error= 1;
+ error= error ? 1 : 2;
}
Field_float::store(nr);
return error;
@@ -4093,7 +4102,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
- error= 1;
+ error= error ? 1 : 2;
}
Field_double::store(nr);
return error;
@@ -4495,6 +4504,8 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
}
}
+ if (error > 1)
+ error= 2;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4791,7 +4802,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
if (str_to_time(from, len, &ltime, &error))
{
tmp=0L;
- error= 1;
+ error= 2;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_TIME, 1);
}
@@ -4813,6 +4824,8 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
from, len, MYSQL_TIMESTAMP_TIME, !error);
error= 1;
}
+ if (error > 1)
+ error= 2;
}
if (ltime.neg)
@@ -5149,7 +5162,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
&error) <= MYSQL_TIMESTAMP_ERROR)
{
tmp=0;
- error= 1;
+ error= 2;
}
else
tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
@@ -5353,7 +5366,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
&error) <= MYSQL_TIMESTAMP_ERROR)
{
tmp=0L;
- error= 1;
+ error= 2;
}
else
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
@@ -5836,7 +5849,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
from= tmpstr.ptr();
length= tmpstr.length();
if (conv_errors)
- error= 1;
+ error= 2;
}
/*
@@ -5860,7 +5873,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
from+= field_charset->cset->scan(field_charset, from, end,
MY_SEQ_SPACES);
if (from != end)
- error= 1;
+ error= 2;
}
if (error)
{
@@ -6242,7 +6255,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
table->in_use->abort_on_warning)
error_code= ER_DATA_TOO_LONG;
set_warning(level, error_code, 1);
- return 1;
+ return 2;
}
return 0;
}
@@ -6685,7 +6698,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
CHARSET_INFO *cs)
- :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
+ :Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length),
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg, cs),
packlength(blob_pack_length)
@@ -6818,11 +6831,16 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
&not_used)))
{
uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
+ if (tmpstr.copy(from, length, cs, field_charset, &conv_errors))
+ {
+ /* Fatal OOM error */
+ bzero(ptr,Field_blob::pack_length());
+ return -1;
+ }
from= tmpstr.ptr();
length= tmpstr.length();
if (conv_errors)
- error= 1;
+ error= 2;
}
copy_length= max_data_length();
@@ -6837,7 +6855,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
copy_length,
&well_formed_error);
if (copy_length < length)
- error= 1;
+ error= 2;
Field_blob::store_length(copy_length);
if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
{ // Must make a copy
@@ -8469,7 +8487,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
else
interval=0;
def=0;
- if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) &&
+ if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
+ !old_field->is_real_null() &&
old_field->ptr && orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
diff --git a/sql/field.h b/sql/field.h
index 258eab9565f..523cf444c30 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -25,6 +25,7 @@
#endif
#define NOT_FIXED_DEC 31
+#define DATETIME_DEC 6
class Send_field;
class Protocol;
@@ -85,6 +86,7 @@ public:
utype unireg_check;
uint32 field_length; // Length of field
+ uint field_index; // field number in fields array
uint16 flags;
uchar null_bit; // Bit used to test null bit
@@ -941,6 +943,7 @@ public:
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
#endif
enum Item_result cmp_type () const { return INT_RESULT; }
+ uint decimals() const { return DATETIME_DEC; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
@@ -1286,7 +1289,7 @@ public:
enum_field_types type() const { return FIELD_TYPE_BIT; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
uint32 key_length() const { return (uint32) field_length + (bit_len > 0); }
- uint32 max_length() { return (uint32) field_length + (bit_len > 0); }
+ uint32 max_length() { return (uint32) field_length * 8 + bit_len; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
void reset(void) { bzero(ptr, field_length); }
@@ -1318,6 +1321,11 @@ public:
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
char *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
+ void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
+ {
+ bit_ptr= bit_ptr_arg;
+ bit_ofs= bit_ofs_arg;
+ }
};
@@ -1329,6 +1337,7 @@ public:
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ uint32 max_length() { return (uint32) create_length; }
uint size_of() const { return sizeof(*this); }
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr) { return Field_bit::store(nr); }
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 15598e59bb9..0dc82666f52 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -324,21 +324,28 @@ static void do_field_real(Copy_field *copy)
static void do_cut_string(Copy_field *copy)
{ // Shorter string field
- memcpy(copy->to_ptr,copy->from_ptr,copy->to_length);
-
- /* Check if we loosed any important characters */
- char *ptr,*end;
- for (ptr=copy->from_ptr+copy->to_length,end=copy->from_ptr+copy->from_length ;
- ptr != end ;
- ptr++)
+ int well_formed_error;
+ CHARSET_INFO *cs= copy->from_field->charset();
+ const char *from_end= copy->from_ptr + copy->from_length;
+ uint copy_length= cs->cset->well_formed_len(cs, copy->from_ptr, from_end,
+ copy->to_length / cs->mbmaxlen,
+ &well_formed_error);
+ if (copy->to_length < copy_length)
+ copy_length= copy->to_length;
+ memcpy(copy->to_ptr, copy->from_ptr, copy_length);
+
+ /* Check if we lost any important characters */
+ if (well_formed_error ||
+ cs->cset->scan(cs, copy->from_ptr + copy_length, from_end,
+ MY_SEQ_SPACES) < (copy->from_length - copy_length))
{
- if (!my_isspace(system_charset_info, *ptr)) // QQ: ucs incompatible
- {
- copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED, 1);
- break;
- }
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
}
+
+ if (copy_length < copy->to_length)
+ cs->cset->fill(cs, copy->to_ptr + copy_length,
+ copy->to_length - copy_length, ' ');
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 30ebd8d59e1..75da43afed5 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -631,7 +631,7 @@ static void make_sortkey(register SORTPARAM *param,
*to++=1;
/* All item->str() to use some extra byte for end null.. */
String tmp((char*) to,sort_field->length+4,cs);
- String *res=item->val_str(&tmp);
+ String *res= item->str_result(&tmp);
if (!res)
{
if (maybe_null)
@@ -673,8 +673,8 @@ static void make_sortkey(register SORTPARAM *param,
}
case INT_RESULT:
{
- longlong value=item->val_int();
- if (maybe_null)
+ longlong value= item->val_int_result();
+ if (maybe_null)
{
*to++=1; /* purecov: inspected */
if (item->null_value)
@@ -715,7 +715,7 @@ static void make_sortkey(register SORTPARAM *param,
}
case DECIMAL_RESULT:
{
- my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf);
+ my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
if (maybe_null)
{
if (item->null_value)
@@ -733,7 +733,7 @@ static void make_sortkey(register SORTPARAM *param,
}
case REAL_RESULT:
{
- double value= item->val_real();
+ double value= item->val_result();
if (maybe_null)
{
if (item->null_value)
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 89210a2f3cd..383652e4a3a 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -462,6 +462,12 @@ static int check_foreign_data_source(FEDERATED_SHARE *share)
}
else
{
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
/*
Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0
if we can connect, then make sure the table exists
@@ -842,7 +848,7 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.length(0);
uint table_name_length, table_base_name_length;
- char *tmp_table_name, *tmp_table_base_name, *table_base_name, *select_query;
+ char *tmp_table_name, *table_base_name, *select_query;
/* share->table_name has the file location - we want the table's name! */
table_base_name= (char*) table->s->table_name;
@@ -963,7 +969,6 @@ const char **ha_federated::bas_ext() const
int ha_federated::open(const char *name, int mode, uint test_if_locked)
{
- int rc;
DBUG_ENTER("ha_federated::open");
if (!(share= get_share(name, table)))
@@ -988,6 +993,12 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_CONNECT_TO_MASTER);
}
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
DBUG_RETURN(0);
}
@@ -1076,7 +1087,7 @@ int ha_federated::write_row(byte *buf)
{
uint x= 0, num_fields= 0;
Field **field;
- ulong current_query_id= 1;
+ query_id_t current_query_id= 1;
ulong tmp_query_id= 1;
uint all_fields_have_same_query_id= 1;
@@ -1387,27 +1398,25 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
int ha_federated::delete_row(const byte *buf)
{
- uint x= 0;
char delete_buffer[IO_SIZE];
char data_buffer[IO_SIZE];
-
String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin);
- delete_string.length(0);
String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin);
- data_string.length(0);
-
DBUG_ENTER("ha_federated::delete_row");
+ delete_string.length(0);
delete_string.append("DELETE FROM `");
delete_string.append(share->table_base_name);
delete_string.append("`");
delete_string.append(" WHERE ");
- for (Field **field= table->field; *field; field++, x++)
+ for (Field **field= table->field; *field; field++)
{
- delete_string.append((*field)->field_name);
+ Field *cur_field= *field;
+ data_string.length(0);
+ delete_string.append(cur_field->field_name);
- if ((*field)->is_null())
+ if (cur_field->is_null_in_record((const uchar*) buf))
{
delete_string.append(" IS ");
data_string.append("NULL");
@@ -1415,17 +1424,15 @@ int ha_federated::delete_row(const byte *buf)
else
{
delete_string.append("=");
- (*field)->val_str(&data_string);
- (*field)->quote_data(&data_string);
+ cur_field->val_str(&data_string, (char*) buf+ cur_field->offset());
+ cur_field->quote_data(&data_string);
}
delete_string.append(data_string);
- data_string.length(0);
-
- if (x + 1 < table->s->fields)
- delete_string.append(" AND ");
+ delete_string.append(" AND ");
}
+ delete_string.length(delete_string.length()-5); // Remove AND
delete_string.append(" LIMIT 1");
DBUG_PRINT("info",
("Delete sql: %s", delete_string.c_ptr_quick()));
@@ -1471,8 +1478,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
__attribute__ ((unused)))
{
char index_value[IO_SIZE];
- char key_value[IO_SIZE];
- char test_value[IO_SIZE];
String index_string(index_value, sizeof(index_value), &my_charset_bin);
index_string.length(0);
uint keylen;
@@ -1538,7 +1543,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
int ha_federated::index_init(uint keynr)
{
- int error;
DBUG_ENTER("ha_federated::index_init");
DBUG_PRINT("info",
("table: '%s' key: %d", table->s->table_name, keynr));
@@ -1570,7 +1574,6 @@ int ha_federated::index_next(byte *buf)
int ha_federated::rnd_init(bool scan)
{
DBUG_ENTER("ha_federated::rnd_init");
- int num_fields, rows;
/*
This 'scan' flag is incredibly important for this handler to work
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index cd655eeb0a9..6e609a94be3 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -65,7 +65,15 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
/* Initialize variables for the opened table */
set_keys_for_scanning();
- update_key_stats();
+ /*
+ We cannot run update_key_stats() here because we do not have a
+ lock on the table. The 'records' count might just be changed
+ temporarily at this moment and we might get wrong statistics (Bug
+ #10178). Instead we request for update. This will be done in
+ ha_heap::info(), which is always called before key statistics are
+ used.
+ */
+ key_stats_ok= FALSE;
}
return (file ? 0 : 1);
}
@@ -118,6 +126,8 @@ void ha_heap::update_key_stats()
}
}
records_changed= 0;
+ /* At the end of update_key_stats() we can proudly claim they are OK. */
+ key_stats_ok= TRUE;
}
@@ -132,7 +142,7 @@ int ha_heap::write_row(byte * buf)
res= heap_write(file,buf);
if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records))
- update_key_stats();
+ key_stats_ok= FALSE;
return res;
}
@@ -145,7 +155,7 @@ int ha_heap::update_row(const byte * old_data, byte * new_data)
res= heap_update(file,old_data,new_data);
if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records)
- update_key_stats();
+ key_stats_ok= FALSE;
return res;
}
@@ -156,7 +166,7 @@ int ha_heap::delete_row(const byte * buf)
res= heap_delete(file,buf);
if (!res && table->s->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
- update_key_stats();
+ key_stats_ok= FALSE;
return res;
}
@@ -278,6 +288,13 @@ void ha_heap::info(uint flag)
delete_length= info.deleted * info.reclength;
if (flag & HA_STATUS_AUTO)
auto_increment_value= info.auto_increment;
+ /*
+ If info() is called for the first time after open(), we will still
+ have to update the key statistics. Hoping that a table lock is now
+ in place.
+ */
+ if (! key_stats_ok)
+ update_key_stats();
}
int ha_heap::extra(enum ha_extra_function operation)
@@ -289,7 +306,7 @@ int ha_heap::delete_all_rows()
{
heap_clear(file);
if (table->s->tmp_table == NO_TMP_TABLE)
- update_key_stats();
+ key_stats_ok= FALSE;
return 0;
}
@@ -448,6 +465,9 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key,
min_key->flag != HA_READ_KEY_EXACT ||
max_key->flag != HA_READ_AFTER_KEY)
return HA_POS_ERROR; // Can only use exact keys
+
+ /* Assert that info() did run. We need current statistics here. */
+ DBUG_ASSERT(key_stats_ok);
return key->rec_per_key[key->key_parts-1];
}
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 2aa065e0d96..7a97c727049 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -29,8 +29,10 @@ class ha_heap: public handler
key_map btree_keys;
/* number of records changed since last statistics update */
uint records_changed;
+ bool key_stats_ok;
public:
- ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {}
+ ha_heap(TABLE *table): handler(table), file(0), records_changed(0),
+ key_stats_ok(0) {}
~ha_heap() {}
const char *table_type() const
{
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 92ec482a468..e33a0939e27 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -146,8 +146,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_buffer_pool_awe_mem_mb,
innobase_buffer_pool_size, innobase_additional_mem_pool_size,
innobase_file_io_threads, innobase_lock_wait_timeout,
- innobase_thread_concurrency, innobase_force_recovery,
- innobase_open_files;
+ innobase_force_recovery, innobase_open_files;
/* The default values for the following char* start-up parameters
are determined in innobase_init below: */
@@ -327,7 +326,7 @@ innodb_srv_conc_enter_innodb(
/*=========================*/
trx_t* trx) /* in: transaction handle */
{
- if (srv_thread_concurrency >= 500) {
+ if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) {
return;
}
@@ -344,7 +343,7 @@ innodb_srv_conc_exit_innodb(
/*========================*/
trx_t* trx) /* in: transaction handle */
{
- if (srv_thread_concurrency >= 500) {
+ if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) {
return;
}
@@ -564,7 +563,7 @@ innobase_mysql_print_thd(
thd = (const THD*) input_thd;
fprintf(f, "MySQL thread id %lu, query id %lu",
- thd->thread_id, thd->query_id);
+ thd->thread_id, (ulong) thd->query_id);
if (thd->host) {
putc(' ', f);
fputs(thd->host, f);
@@ -1045,6 +1044,18 @@ mysql_get_identifier_quote_char(
}
/**************************************************************************
+Determines if the currently running transaction has been interrupted. */
+extern "C"
+ibool
+trx_is_interrupted(
+/*===============*/
+ /* out: TRUE if interrupted */
+ trx_t* trx) /* in: transaction */
+{
+ return(trx && trx->mysql_thd && ((THD*) trx->mysql_thd)->killed);
+}
+
+/**************************************************************************
Obtain a pointer to the MySQL THD object, as in current_thd(). This
definition must match the one in sql/ha_innodb.cc! */
extern "C"
@@ -1302,8 +1313,8 @@ innobase_init(void)
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
- data_mysql_latin1_swedish_charset_coll =
- (ulint)my_charset_latin1.number;
+ ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL ==
+ my_charset_latin1.number);
/* Store the latin1_swedish_ci character ordering table to InnoDB. For
non-latin1_swedish_ci charsets we use the MySQL comparison functions,
@@ -1485,8 +1496,8 @@ innobase_start_trx_and_assign_read_view(
/*********************************************************************
Commits a transaction in an InnoDB database or marks an SQL statement
ended. */
-
-static int
+static
+int
innobase_commit(
/*============*/
/* out: 0 */
@@ -1794,7 +1805,7 @@ try_again:
fprintf(stderr,
"InnoDB: This transaction needs it to be sent up to\n"
"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name,
- (uint)trx->repl_wait_binlog_pos);
+ (ulong)trx->repl_wait_binlog_pos);
innobase_repl_state = 0;
@@ -2867,6 +2878,8 @@ build_template(
ibool fetch_all_in_key = FALSE;
ibool fetch_primary_key_cols = FALSE;
ulint i;
+ /* byte offset of the end of last requested column */
+ ulint mysql_prefix_len = 0;
if (prebuilt->select_lock_type == LOCK_X) {
/* We always retrieve the whole clustered index record if we
@@ -2942,21 +2955,44 @@ build_template(
templ = prebuilt->mysql_template + n_requested_fields;
field = table->field[i];
- ibool index_contains_field=
- dict_index_contains_col_or_prefix(index, i);
+ if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
+ /* Decide which columns we should fetch
+ and which we can skip. */
+ register const ibool index_contains_field =
+ dict_index_contains_col_or_prefix(index, i);
+
+ if (!index_contains_field && prebuilt->read_just_key) {
+ /* If this is a 'key read', we do not need
+ columns that are not in the key */
- if (templ_type == ROW_MYSQL_REC_FIELDS &&
- ((prebuilt->read_just_key && !index_contains_field) ||
- (!(fetch_all_in_key && index_contains_field) &&
- !(fetch_primary_key_cols &&
- dict_table_col_in_clustered_key(index->table, i)) &&
- thd->query_id != field->query_id))) {
+ goto skip_field;
+ }
+
+ if (index_contains_field && fetch_all_in_key) {
+ /* This field is needed in the query */
+
+ goto include_field;
+ }
+
+ if (thd->query_id == field->query_id) {
+ /* This field is needed in the query */
+
+ goto include_field;
+ }
+
+ if (fetch_primary_key_cols
+ && dict_table_col_in_clustered_key(index->table,
+ i)) {
+ /* This field is needed in the query */
+
+ goto include_field;
+ }
/* This field is not needed in the query, skip it */
goto skip_field;
}
-
+include_field:
n_requested_fields++;
templ->col_no = i;
@@ -2987,6 +3023,11 @@ build_template(
get_field_offset(table, field);
templ->mysql_col_len = (ulint) field->pack_length();
+ if (mysql_prefix_len < templ->mysql_col_offset
+ + templ->mysql_col_len) {
+ mysql_prefix_len = templ->mysql_col_offset
+ + templ->mysql_col_len;
+ }
templ->type = index->table->cols[i].type.mtype;
templ->mysql_type = (ulint)field->type();
@@ -3009,6 +3050,7 @@ skip_field:
}
prebuilt->n_template = n_requested_fields;
+ prebuilt->mysql_prefix_len = mysql_prefix_len;
if (index != clust_index && prebuilt->need_to_access_clustered) {
/* Change rec_field_no's to correspond to the clustered index
@@ -3080,7 +3122,7 @@ ha_innobase::write_row(
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
dict_table_t* src_table;
- ibool mode;
+ ulint mode;
num_write_row = 0;
@@ -3519,7 +3561,9 @@ ha_innobase::delete_row(
}
/**************************************************************************
-Deletes a lock set to a row */
+Removes a new lock set on a row. This can be called after a row has been read
+in the processing of an UPDATE or a DELETE query, if the option
+innodb_locks_unsafe_for_binlog is set. */
void
ha_innobase::unlock_row(void)
@@ -3537,8 +3581,10 @@ ha_innobase::unlock_row(void)
mem_analyze_corruption((byte *) prebuilt->trx);
ut_error;
}
-
- row_unlock_for_mysql(prebuilt);
+
+ if (srv_locks_unsafe_for_binlog) {
+ row_unlock_for_mysql(prebuilt, FALSE);
+ }
}
/**********************************************************************
@@ -5972,6 +6018,7 @@ ha_innobase::external_lock(
reads. */
prebuilt->select_lock_type = LOCK_S;
+ prebuilt->stored_select_lock_type = LOCK_S;
}
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
@@ -5991,7 +6038,7 @@ ha_innobase::external_lock(
ulint error;
error = row_lock_table_for_mysql(prebuilt,
- NULL, LOCK_TABLE_EXP);
+ NULL, 0);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(
@@ -6011,10 +6058,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
- if (trx->n_lock_table_exp) {
- row_unlock_tables_for_mysql(trx);
- }
-
/* If the MySQL lock count drops to zero we know that the current SQL
statement has ended */
@@ -6055,7 +6098,7 @@ user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */
int
ha_innobase::transactional_table_lock(
/*==================================*/
- /* out: 0 */
+ /* out: error code */
THD* thd, /* in: handle to the user thread */
int lock_type) /* in: lock type */
{
@@ -6119,8 +6162,7 @@ ha_innobase::transactional_table_lock(
if (thd->in_lock_tables && thd->variables.innodb_table_locks) {
ulint error = DB_SUCCESS;
- error = row_lock_table_for_mysql(prebuilt,NULL,
- LOCK_TABLE_TRANSACTIONAL);
+ error = row_lock_table_for_mysql(prebuilt, NULL, 0);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql((int) error, user_thd);
@@ -6548,12 +6590,14 @@ the value of the auto-inc counter. */
int
ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/
- /* out: 0 or error code: deadlock or
- lock wait timeout */
+ /* out: 0 or error code: deadlock or lock wait
+ timeout */
longlong* ret) /* out: auto-inc value */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
longlong auto_inc;
+ ulint old_select_lock_type;
+ ibool trx_was_not_started = FALSE;
int error;
ut_a(prebuilt);
@@ -6561,6 +6605,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
(trx_t*) current_thd->ha_data[innobase_hton.slot]);
ut_a(prebuilt->table);
+ if (prebuilt->trx->conc_state == TRX_NOT_STARTED) {
+ trx_was_not_started = TRUE;
+ }
+
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@@ -6572,7 +6620,9 @@ ha_innobase::innobase_read_and_init_auto_inc(
/* Already initialized */
*ret = auto_inc;
- return(0);
+ error = 0;
+
+ goto func_exit_early;
}
error = row_lock_table_autoinc_for_mysql(prebuilt);
@@ -6580,7 +6630,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
- goto func_exit;
+ goto func_exit_early;
}
/* Check again if someone has initialized the counter meanwhile */
@@ -6589,30 +6639,37 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (auto_inc != 0) {
*ret = auto_inc;
- return(0);
+ error = 0;
+
+ goto func_exit_early;
}
(void) extra(HA_EXTRA_KEYREAD);
index_init(table->s->next_number_index);
- /* We use an exclusive lock when we read the max key value from the
- auto-increment column index. This is because then build_template will
- advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
- id of the auto-increment column is not changed, and previously InnoDB
- did not fetch it, causing SHOW TABLE STATUS to show wrong values
- for the autoinc column. */
-
- prebuilt->select_lock_type = LOCK_X;
+ /* Starting from 5.0.9, we use a consistent read to read the auto-inc
+ column maximum value. This eliminates the spurious deadlocks caused
+ by the row X-lock that we previously used. Note the following flaw
+ in our algorithm: if some other user meanwhile UPDATEs the auto-inc
+ column, our consistent read will not return the largest value. We
+ accept this flaw, since the deadlocks were a bigger trouble. */
- /* Play safe and also give in another way the hint to fetch
- all columns in the key: */
+ /* Fetch all the columns in the key */
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
- prebuilt->trx->mysql_n_tables_locked += 1;
-
+ old_select_lock_type = prebuilt->select_lock_type;
+ prebuilt->select_lock_type = LOCK_NONE;
+
+ /* Eliminate an InnoDB error print that happens when we try to SELECT
+ from a table when no table has been locked in ::external_lock(). */
+ prebuilt->trx->n_mysql_tables_in_use++;
+
error = index_last(table->record[1]);
+ prebuilt->trx->n_mysql_tables_in_use--;
+ prebuilt->select_lock_type = old_select_lock_type;
+
if (error) {
if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */
@@ -6620,7 +6677,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
error = 0;
} else {
- /* Deadlock or a lock wait timeout */
+ /* This should not happen in a consistent read */
+ fprintf(stderr,
+"InnoDB: Error: consistent read of auto-inc column returned %lu\n",
+ (ulong)error);
auto_inc = -1;
goto func_exit;
@@ -6640,7 +6700,18 @@ func_exit:
*ret = auto_inc;
- return(error);
+func_exit_early:
+ /* Since MySQL does not seem to call autocommit after SHOW TABLE
+ STATUS (even if we would register the trx here), we must commit our
+ transaction here if it was started here. This is to eliminate a
+ dangling transaction. */
+
+ if (trx_was_not_started) {
+
+ innobase_commit_low(prebuilt->trx);
+ }
+
+ return(error);
}
/***********************************************************************
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 4c0f5209af9..90cae3998ed 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -218,7 +218,7 @@ extern long innobase_log_file_size, innobase_log_buffer_size;
extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size;
extern long innobase_buffer_pool_awe_mem_mb;
extern long innobase_file_io_threads, innobase_lock_wait_timeout;
-extern long innobase_force_recovery, innobase_thread_concurrency;
+extern long innobase_force_recovery;
extern long innobase_open_files;
extern char *innobase_data_home_dir, *innobase_data_file_path;
extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 24ccbe5073b..27019c94284 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -41,7 +41,7 @@ static const int parallelism= 0;
// Default value for max number of transactions
// createable against NDB from this handler
-static const int max_transactions= 256;
+static const int max_transactions= 2;
static const char *ha_ndb_ext=".ndb";
@@ -341,7 +341,7 @@ void ha_ndbcluster::records_update()
{
Ndb *ndb= get_ndb();
struct Ndb_statistics stat;
- if(ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){
+ if (ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){
mean_rec_length= stat.row_size;
data_file_length= stat.fragment_memory;
info->records= stat.row_count;
@@ -448,27 +448,27 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index;
NDB_INDEX_TYPE idx_type= m_index[i].type;
- switch(idx_type) {
- case(PRIMARY_KEY_ORDERED_INDEX):
- case(ORDERED_INDEX):
+ switch (idx_type) {
+ case PRIMARY_KEY_ORDERED_INDEX:
+ case ORDERED_INDEX:
if (global)
dict->invalidateIndex(index->getName(), m_tabname);
else
dict->removeCachedIndex(index->getName(), m_tabname);
break;
- case(UNIQUE_ORDERED_INDEX):
+ case UNIQUE_ORDERED_INDEX:
if (global)
dict->invalidateIndex(index->getName(), m_tabname);
else
dict->removeCachedIndex(index->getName(), m_tabname);
- case(UNIQUE_INDEX):
+ case UNIQUE_INDEX:
if (global)
dict->invalidateIndex(unique_index->getName(), m_tabname);
else
dict->removeCachedIndex(unique_index->getName(), m_tabname);
break;
- case(PRIMARY_KEY_INDEX):
- case(UNDEFINED_INDEX):
+ case PRIMARY_KEY_INDEX:
+ case UNDEFINED_INDEX:
break;
}
}
@@ -511,8 +511,15 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans)
DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
err.code, res));
if (res == HA_ERR_FOUND_DUPP_KEY)
- m_dupkey= table->s->primary_key;
-
+ {
+ if (m_rows_to_insert == 1)
+ m_dupkey= table->s->primary_key;
+ else
+ {
+ /* We are batching inserts, offending key is not available */
+ m_dupkey= (uint) -1;
+ }
+ }
DBUG_RETURN(res);
}
@@ -540,13 +547,12 @@ bool ha_ndbcluster::get_error_message(int error,
}
+#ifndef DBUG_OFF
/*
Check if type is supported by NDB.
- TODO Use this once in open(), not in every operation
-
*/
-static inline bool ndb_supported_type(enum_field_types type)
+static bool ndb_supported_type(enum_field_types type)
{
switch (type) {
case MYSQL_TYPE_TINY:
@@ -581,6 +587,7 @@ static inline bool ndb_supported_type(enum_field_types type)
}
return FALSE;
}
+#endif /* !DBUG_OFF */
/*
@@ -610,15 +617,10 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
pack_len));
DBUG_DUMP("key", (char*)field_ptr, pack_len);
- if (ndb_supported_type(field->type()))
- {
- if (! (field->flags & BLOB_FLAG))
- // Common implementation for most field types
- DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
- }
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
+ DBUG_ASSERT(ndb_supported_type(field->type()));
+ DBUG_ASSERT(! (field->flags & BLOB_FLAG));
+ // Common implementation for most field types
+ DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
}
@@ -637,7 +639,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
pack_len, field->is_null()?"Y":"N"));
DBUG_DUMP("value", (char*) field_ptr, pack_len);
- if (ndb_supported_type(field->type()))
+ DBUG_ASSERT(ndb_supported_type(field->type()));
{
// ndb currently does not support size 0
uint32 empty_field;
@@ -715,9 +717,6 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
}
DBUG_RETURN(1);
}
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
}
@@ -812,9 +811,8 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
if (field != NULL)
{
- DBUG_ASSERT(buf);
- if (ndb_supported_type(field->type()))
- {
+ DBUG_ASSERT(buf);
+ DBUG_ASSERT(ndb_supported_type(field->type()));
DBUG_ASSERT(field->ptr != NULL);
if (! (field->flags & BLOB_FLAG))
{
@@ -845,10 +843,6 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0);
}
DBUG_RETURN(1);
- }
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
}
// Used for hidden key only
@@ -1255,36 +1249,18 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
}
-int ha_ndbcluster::set_primary_key_from_old_data(NdbOperation *op, const byte *old_data)
-{
- KEY* key_info= table->key_info + table->s->primary_key;
- KEY_PART_INFO* key_part= key_info->key_part;
- KEY_PART_INFO* end= key_part+key_info->key_parts;
- DBUG_ENTER("set_primary_key_from_old_data");
-
- for (; key_part != end; key_part++)
- {
- Field* field= key_part->field;
- if (set_ndb_key(op, field,
- key_part->fieldnr-1, old_data+key_part->offset))
- ERR_RETURN(op->getNdbError());
- }
- DBUG_RETURN(0);
-}
-
-
-int ha_ndbcluster::set_primary_key(NdbOperation *op)
+int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const byte *record)
{
- DBUG_ENTER("set_primary_key");
KEY* key_info= table->key_info + table->s->primary_key;
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
+ DBUG_ENTER("set_primary_key_from_record");
for (; key_part != end; key_part++)
{
Field* field= key_part->field;
if (set_ndb_key(op, field,
- key_part->fieldnr-1, field->ptr))
+ key_part->fieldnr-1, record+key_part->offset))
ERR_RETURN(op->getNdbError());
}
DBUG_RETURN(0);
@@ -1393,7 +1369,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
return res;
}
- if((res= define_read_attrs(buf, op)))
+ if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
if (execute_no_commit_ie(this,trans) != 0)
@@ -1429,11 +1405,9 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
op->readTuple(lm) != 0)
ERR_RETURN(trans->getNdbError());
-
int res;
- if ((res= set_primary_key_from_old_data(op, old_data)))
+ if ((res= set_primary_key_from_record(op, old_data)))
ERR_RETURN(trans->getNdbError());
-
// Read all unreferenced non-key field(s)
for (i= 0; i < no_fields; i++)
{
@@ -1476,7 +1450,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
Peek to check if a particular row already exists
*/
-int ha_ndbcluster::peek_row()
+int ha_ndbcluster::peek_row(const byte *record)
{
NdbTransaction *trans= m_active_trans;
NdbOperation *op;
@@ -1489,7 +1463,7 @@ int ha_ndbcluster::peek_row()
ERR_RETURN(trans->getNdbError());
int res;
- if ((res= set_primary_key(op)))
+ if ((res= set_primary_key_from_record(op, record)))
ERR_RETURN(trans->getNdbError());
if (execute_no_commit_ie(this,trans) != 0)
@@ -1523,10 +1497,10 @@ int ha_ndbcluster::unique_index_read(const byte *key,
ERR_RETURN(trans->getNdbError());
// Set secondary index key(s)
- if((res= set_index_key(op, table->key_info + active_index, key)))
+ if ((res= set_index_key(op, table->key_info + active_index, key)))
DBUG_RETURN(res);
- if((res= define_read_attrs(buf, op)))
+ if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
if (execute_no_commit_ie(this,trans) != 0)
@@ -1586,7 +1560,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
if (execute_commit(this,trans) != 0)
DBUG_RETURN(-1);
- if(trans->restart() != 0)
+ if (trans->restart() != 0)
{
DBUG_ASSERT(0);
DBUG_RETURN(-1);
@@ -1624,7 +1598,7 @@ inline int ha_ndbcluster::next_result(byte *buf)
if (!m_active_cursor)
DBUG_RETURN(HA_ERR_END_OF_FILE);
- if((res= fetch_next(m_active_cursor)) == 0)
+ if ((res= fetch_next(m_active_cursor)) == 0)
{
DBUG_PRINT("info", ("One more record found"));
@@ -1632,7 +1606,7 @@ inline int ha_ndbcluster::next_result(byte *buf)
table->status= 0;
DBUG_RETURN(0);
}
- else if(res == 1)
+ else if (res == 1)
{
// No more records
table->status= STATUS_NOT_FOUND;
@@ -1863,7 +1837,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
DBUG_ASSERT(op->getSorted() == sorted);
DBUG_ASSERT(op->getLockMode() ==
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
- if(op->reset_bounds(m_force_send))
+ if (op->reset_bounds(m_force_send))
DBUG_RETURN(ndb_err(m_active_trans));
}
@@ -1909,7 +1883,7 @@ int ha_ndbcluster::full_table_scan(byte *buf)
m_active_cursor= op;
if (generate_scan_filter(m_cond_stack, op))
DBUG_RETURN(ndb_err(trans));
- if((res= define_read_attrs(buf, op)))
+ if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
if (execute_no_commit(this,trans) != 0)
@@ -1934,7 +1908,7 @@ int ha_ndbcluster::write_row(byte *record)
if (m_ignore_dup_key && table->s->primary_key != MAX_KEY)
{
- int peek_res= peek_row();
+ int peek_res= peek_row(record);
if (!peek_res)
{
@@ -1988,9 +1962,7 @@ int ha_ndbcluster::write_row(byte *record)
m_skip_auto_increment= !auto_increment_column_changed;
}
- if ((res= (m_primary_key_update ?
- set_primary_key_from_old_data(op, record)
- : set_primary_key(op))))
+ if ((res= set_primary_key_from_record(op, record)))
return res;
}
@@ -2047,7 +2019,7 @@ int ha_ndbcluster::write_row(byte *record)
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
- if(trans->restart() != 0)
+ if (trans->restart() != 0)
{
DBUG_ASSERT(0);
DBUG_RETURN(-1);
@@ -2130,7 +2102,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
if ((table->s->primary_key != MAX_KEY) &&
(key_cmp(table->s->primary_key, old_data, new_data)))
{
- int read_res, insert_res, delete_res;
+ int read_res, insert_res, delete_res, undo_res;
DBUG_PRINT("info", ("primary key update, doing pk read+delete+insert"));
// Get all old fields, since we optimize away fields not in query
@@ -2159,9 +2131,14 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_PRINT("info", ("insert failed"));
if (trans->commitStatus() == NdbConnection::Started)
{
- // Undo write_row(new_data)
+ // Undo delete_row(old_data)
m_primary_key_update= TRUE;
- insert_res= write_row((byte *)old_data);
+ undo_res= write_row((byte *)old_data);
+ if (undo_res)
+ push_warning(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ undo_res,
+ "NDB failed undoing delete at primary key update");
m_primary_key_update= FALSE;
}
DBUG_RETURN(insert_res);
@@ -2210,7 +2187,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
else
{
int res;
- if ((res= set_primary_key_from_old_data(op, old_data)))
+ if ((res= set_primary_key_from_record(op, old_data)))
DBUG_RETURN(res);
}
}
@@ -2295,10 +2272,8 @@ int ha_ndbcluster::delete_row(const byte *record)
else
{
int res;
- if ((res= (m_primary_key_update ?
- set_primary_key_from_old_data(op, record)
- : set_primary_key(op))))
- return res;
+ if ((res= set_primary_key_from_record(op, record)))
+ return res;
}
}
@@ -2426,7 +2401,7 @@ void ha_ndbcluster::print_results()
field= table->field[f];
if (!(value= m_value[f]).ptr)
{
- my_snprintf(buf, sizeof(buf), "not read");
+ strmov(buf, "not read");
goto print_value;
}
@@ -2436,7 +2411,7 @@ void ha_ndbcluster::print_results()
{
if (value.rec->isNULL())
{
- my_snprintf(buf, sizeof(buf), "NULL");
+ strmov(buf, "NULL");
goto print_value;
}
type.length(0);
@@ -2450,10 +2425,8 @@ void ha_ndbcluster::print_results()
NdbBlob *ndb_blob= value.blob;
bool isNull= TRUE;
ndb_blob->getNull(isNull);
- if (isNull) {
- my_snprintf(buf, sizeof(buf), "NULL");
- goto print_value;
- }
+ if (isNull)
+ strmov(buf, "NULL");
}
print_value:
@@ -2493,7 +2466,7 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
for (; curr_part != end_part && key < end_ptr; curr_part++)
{
- if(curr_part->null_bit && *key)
+ if (curr_part->null_bit && *key)
return 1;
key += curr_part->store_length;
@@ -2517,7 +2490,7 @@ int ha_ndbcluster::index_read(byte *buf,
case PRIMARY_KEY_INDEX:
if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len)
{
- if(m_active_cursor && (error= close_scan()))
+ if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
DBUG_RETURN(pk_read(key, key_len, buf));
}
@@ -2531,7 +2504,7 @@ int ha_ndbcluster::index_read(byte *buf,
if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len &&
!check_null_in_key(key_info, key, key_len))
{
- if(m_active_cursor && (error= close_scan()))
+ if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
DBUG_RETURN(unique_index_read(key, key_len, buf));
}
@@ -2643,7 +2616,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
start_key->length == key_info->key_length &&
start_key->flag == HA_READ_KEY_EXACT)
{
- if(m_active_cursor && (error= close_scan()))
+ if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
error= pk_read(start_key->key, start_key->length, buf);
DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
@@ -2656,7 +2629,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
start_key->flag == HA_READ_KEY_EXACT &&
!check_null_in_key(key_info, start_key->key, start_key->length))
{
- if(m_active_cursor && (error= close_scan()))
+ if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
error= unique_index_read(start_key->key, start_key->length, buf);
DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
@@ -2703,7 +2676,7 @@ int ha_ndbcluster::rnd_init(bool scan)
{
if (!scan)
DBUG_RETURN(1);
- if(cursor->restart(m_force_send) != 0)
+ if (cursor->restart(m_force_send) != 0)
{
DBUG_ASSERT(0);
DBUG_RETURN(-1);
@@ -3132,6 +3105,13 @@ double ha_ndbcluster::scan_time()
DBUG_RETURN(res);
}
+/*
+ Convert MySQL table locks into locks supported by Ndb Cluster.
+ Note that MySQL Cluster does currently not support distributed
+ table locks, so to be safe one should set cluster in Single
+ User Mode, before relying on table locks when updating tables
+ from several MySQL servers
+*/
THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
THR_LOCK_DATA **to,
@@ -3147,7 +3127,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
/* Since NDB does not currently have table locks
this is treated as a ordinary lock */
- if ((lock_type >= TL_WRITE_ALLOW_WRITE &&
+ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
lock_type <= TL_WRITE) && !thd->in_lock_tables)
lock_type= TL_WRITE_ALLOW_WRITE;
@@ -3466,7 +3446,7 @@ int ndbcluster_commit(THD *thd, bool all)
}
ndb->closeTransaction(trans);
- if(all)
+ if (all)
thd_ndb->all= NULL;
else
thd_ndb->stmt= NULL;
@@ -3516,7 +3496,7 @@ int ndbcluster_rollback(THD *thd, bool all)
}
ndb->closeTransaction(trans);
- if(all)
+ if (all)
thd_ndb->all= NULL;
else
thd_ndb->stmt= NULL;
@@ -3772,7 +3752,8 @@ static int create_ndb_column(NDBCOL &col,
col.setType(NDBCOL::Char);
col.setLength(field->pack_length());
break;
- case MYSQL_TYPE_BIT: {
+ case MYSQL_TYPE_BIT:
+ {
int no_of_bits= field->field_length*8 + ((Field_bit *) field)->bit_len;
col.setType(NDBCOL::Bit);
if (!no_of_bits)
@@ -3907,7 +3888,7 @@ int ha_ndbcluster::create(const char *name,
if ((my_errno= create_ndb_column(col, field, info)))
DBUG_RETURN(my_errno);
tab.addColumn(col);
- if(col.getPrimaryKey())
+ if (col.getPrimaryKey())
pk_length += (field->pack_length() + 3) / 4;
}
@@ -3940,7 +3921,7 @@ int ha_ndbcluster::create(const char *name,
{
NdbDictionary::Column * col= tab.getColumn(i);
int size= pk_length + (col->getPartSize()+3)/4 + 7;
- if(size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
+ if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
(pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS)
{
size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7;
@@ -4168,12 +4149,10 @@ ulonglong ha_ndbcluster::get_auto_increment()
m_rows_to_insert+= m_autoincrement_prefetch;
}
cache_size=
- (int)
- (m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ?
- m_rows_to_insert - m_rows_inserted
- : (m_rows_to_insert > m_autoincrement_prefetch) ?
- m_rows_to_insert
- : m_autoincrement_prefetch;
+ (int) ((m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ?
+ m_rows_to_insert - m_rows_inserted :
+ ((m_rows_to_insert > m_autoincrement_prefetch) ?
+ m_rows_to_insert : m_autoincrement_prefetch));
auto_value= NDB_FAILED_AUTO_INCREMENT;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
do {
@@ -4446,7 +4425,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
{
const NdbError err= dict->getNdbError();
if (err.code == 709)
- DBUG_RETURN(1);
+ DBUG_RETURN(-1);
ERR_RETURN(err);
}
DBUG_PRINT("info", ("Found table %s", tab->getName()));
@@ -4454,13 +4433,15 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
len= tab->getFrmLength();
if (len == 0 || tab->getFrmData() == NULL)
{
- DBUG_PRINT("No frm data found",
- ("Table is probably created via NdbApi"));
- DBUG_RETURN(2);
+ DBUG_PRINT("error", ("No frm data found."));
+ DBUG_RETURN(1);
}
if (unpackfrm(&data, &len, tab->getFrmData()))
- DBUG_RETURN(3);
+ {
+ DBUG_PRINT("error", ("Could not unpack table"));
+ DBUG_RETURN(1);
+ }
*frmlen= len;
*frmblob= data;
@@ -4473,11 +4454,11 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
*/
-int ndbcluster_table_exists(THD* thd, const char *db, const char *name)
+int ndbcluster_table_exists_in_engine(THD* thd, const char *db, const char *name)
{
const NDBTAB* tab;
Ndb* ndb;
- DBUG_ENTER("ndbcluster_table_exists");
+ DBUG_ENTER("ndbcluster_table_exists_in_engine");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
if (!(ndb= check_ndb_in_thd(thd)))
@@ -4656,7 +4637,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
DBUG_PRINT("info", ("%s existed on disk", name));
// The .ndb file exists on disk, but it's not in list of tables in ndb
// Verify that handler agrees table is gone.
- if (ndbcluster_table_exists(thd, db, file_name) == 0)
+ if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0)
{
DBUG_PRINT("info", ("NDB says %s does not exists", file_name));
it.remove();
@@ -4709,8 +4690,8 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
List_iterator_fast<char> it2(create_list);
while ((file_name=it2++))
{
- DBUG_PRINT("info", ("Table %s need discovery", name));
- if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0)
+ DBUG_PRINT("info", ("Table %s need discovery", file_name));
+ if (ha_create_table_from_engine(thd, db, file_name) == 0)
files->push_back(thd->strdup(file_name));
}
@@ -4775,7 +4756,7 @@ ndbcluster_init()
g_ndb_cluster_connection->get_connected_port()));
g_ndb_cluster_connection->wait_until_ready(10,3);
}
- else if(res == 1)
+ else if (res == 1)
{
if (g_ndb_cluster_connection->start_connect_thread(connect_callback))
{
@@ -4823,7 +4804,7 @@ ndbcluster_init()
DBUG_RETURN(&ndbcluster_hton);
ndbcluster_init_error:
- if(g_ndb)
+ if (g_ndb)
delete g_ndb;
g_ndb= NULL;
if (g_ndb_cluster_connection)
@@ -4852,7 +4833,7 @@ bool ndbcluster_end()
(void) pthread_cond_signal(&COND_ndb_util_thread);
(void) pthread_mutex_unlock(&LOCK_ndb_util_thread);
- if(g_ndb)
+ if (g_ndb)
delete g_ndb;
g_ndb= NULL;
if (g_ndb_cluster_connection)
@@ -5102,7 +5083,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
}
pthread_mutex_lock(&share->mutex);
- if(share->commit_count_lock == lock)
+ if (share->commit_count_lock == lock)
{
DBUG_PRINT("info", ("Setting commit_count to %llu", stat.commit_count));
share->commit_count= stat.commit_count;
@@ -5593,9 +5574,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
for (; multi_range_curr<multi_range_end && curr+reclength <= end_of_buffer;
multi_range_curr++)
{
- switch(index_type){
+ switch (index_type){
+ case PRIMARY_KEY_ORDERED_INDEX:
+ if (!(multi_range_curr->start_key.length == key_info->key_length &&
+ multi_range_curr->start_key.flag == HA_READ_KEY_EXACT))
+ goto range;
+ /* fall through */
case PRIMARY_KEY_INDEX:
- pk:
{
multi_range_curr->range_flag |= UNIQUE_RANGE;
if ((op= m_active_trans->getNdbOperation(tab)) &&
@@ -5609,8 +5594,14 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
break;
}
break;
+ case UNIQUE_ORDERED_INDEX:
+ if (!(multi_range_curr->start_key.length == key_info->key_length &&
+ multi_range_curr->start_key.flag == HA_READ_KEY_EXACT &&
+ !check_null_in_key(key_info, multi_range_curr->start_key.key,
+ multi_range_curr->start_key.length)))
+ goto range;
+ /* fall through */
case UNIQUE_INDEX:
- sk:
{
multi_range_curr->range_flag |= UNIQUE_RANGE;
if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) &&
@@ -5623,19 +5614,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
break;
}
- case PRIMARY_KEY_ORDERED_INDEX:
- if (multi_range_curr->start_key.length == key_info->key_length &&
- multi_range_curr->start_key.flag == HA_READ_KEY_EXACT)
- goto pk;
- goto range;
- case UNIQUE_ORDERED_INDEX:
- if (multi_range_curr->start_key.length == key_info->key_length &&
- multi_range_curr->start_key.flag == HA_READ_KEY_EXACT &&
- !check_null_in_key(key_info, multi_range_curr->start_key.key,
- multi_range_curr->start_key.length))
- goto sk;
- goto range;
- case ORDERED_INDEX: {
+ case ORDERED_INDEX:
+ {
range:
multi_range_curr->range_flag &= ~(uint)UNIQUE_RANGE;
if (scanOp == 0)
@@ -5646,7 +5626,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
DBUG_ASSERT(scanOp->getSorted() == sorted);
DBUG_ASSERT(scanOp->getLockMode() ==
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
- if(scanOp->reset_bounds(m_force_send))
+ if (scanOp->reset_bounds(m_force_send))
DBUG_RETURN(ndb_err(m_active_trans));
end_of_buffer -= reclength;
@@ -5672,7 +5652,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
DBUG_RETURN(res);
break;
}
- case(UNDEFINED_INDEX):
+ case UNDEFINED_INDEX:
DBUG_ASSERT(FALSE);
DBUG_RETURN(1);
break;
@@ -5781,7 +5761,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
DBUG_MULTI_RANGE(6);
// First fetch from cursor
DBUG_ASSERT(range_no == -1);
- if((res= m_multi_cursor->nextResult(true)))
+ if ((res= m_multi_cursor->nextResult(true)))
{
goto close_scan;
}
@@ -5884,7 +5864,7 @@ ha_ndbcluster::update_table_comment(
const char* comment)/* in: table comment defined by user */
{
uint length= strlen(comment);
- if(length > 64000 - 3)
+ if (length > 64000 - 3)
{
return((char*)comment); /* string too long */
}
@@ -5911,9 +5891,9 @@ ha_ndbcluster::update_table_comment(
return (char*)comment;
}
- snprintf(str,fmt_len_plus_extra,fmt,comment,
- length > 0 ? " ":"",
- tab->getReplicaCount());
+ my_snprintf(str,fmt_len_plus_extra,fmt,comment,
+ length > 0 ? " ":"",
+ tab->getReplicaCount());
return str;
}
@@ -6012,7 +5992,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func,
lock= share->commit_count_lock;
pthread_mutex_unlock(&share->mutex);
- if(ndb_get_table_statistics(ndb, tabname, &stat) == 0)
+ if (ndb_get_table_statistics(ndb, tabname, &stat) == 0)
{
DBUG_PRINT("ndb_util_thread",
("Table: %s, commit_count: %llu, rows: %llu",
@@ -6047,7 +6027,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func,
abstime.tv_sec= tick_time.tv_sec;
abstime.tv_nsec= tick_time.tv_usec * 1000;
- if(msecs >= 1000){
+ if (msecs >= 1000){
secs= msecs / 1000;
msecs= msecs % 1000;
}
@@ -6156,17 +6136,18 @@ void ndb_serialize_cond(const Item *item, void *arg)
{
DBUG_PRINT("info", ("Skiping argument %d", context->skip));
context->skip--;
- switch(item->type()) {
- case (Item::FUNC_ITEM): {
+ switch (item->type()) {
+ case Item::FUNC_ITEM:
+ {
Item_func *func_item= (Item_func *) item;
context->skip+= func_item->argument_count();
break;
}
- case(Item::INT_ITEM):
- case(Item::REAL_ITEM):
- case(Item::STRING_ITEM):
- case(Item::VARBIN_ITEM):
- case(Item::DECIMAL_ITEM):
+ case Item::INT_ITEM:
+ case Item::REAL_ITEM:
+ case Item::STRING_ITEM:
+ case Item::VARBIN_ITEM:
+ case Item::DECIMAL_ITEM:
break;
default:
context->supported= FALSE;
@@ -6185,8 +6166,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
(func_item= rewrite_context->func_item) &&
rewrite_context->count++ == 0)
{
- switch(func_item->functype()) {
- case(Item_func::BETWEEN):
+ switch (func_item->functype()) {
+ case Item_func::BETWEEN:
/*
Rewrite
<field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
@@ -6196,7 +6177,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
LT(<field>|<const>, <const2>|<field2>), END()
*/
- case(Item_func::IN_FUNC): {
+ case Item_func::IN_FUNC:
+ {
/*
Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
to <field>|<const> = <const1>|<field1> OR
@@ -6261,17 +6243,18 @@ void ndb_serialize_cond(const Item *item, void *arg)
{
Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
const Item_func *func_item= rewrite_context->func_item;
- switch(func_item->functype()) {
- case(Item_func::BETWEEN): {
- /*
- Rewrite
- <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
- to <field>|<const> > <const1>|<field1> AND
- <field>|<const> < <const2>|<field2>
- or actually in prefix format
- BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
- LT(<field>|<const>, <const2>|<field2>), END()
- */
+ switch (func_item->functype()) {
+ case Item_func::BETWEEN:
+ {
+ /*
+ Rewrite
+ <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
+ to <field>|<const> > <const1>|<field1> AND
+ <field>|<const> < <const2>|<field2>
+ or actually in prefix format
+ BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
+ LT(<field>|<const>, <const2>|<field2>), END()
+ */
if (rewrite_context->count == 2)
{
// Lower limit of BETWEEN
@@ -6293,7 +6276,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
break;
}
- case(Item_func::IN_FUNC): {
+ case Item_func::IN_FUNC:
+ {
/*
Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
to <field>|<const> = <const1>|<field1> OR
@@ -6342,8 +6326,10 @@ void ndb_serialize_cond(const Item *item, void *arg)
curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
}
else
- switch(item->type()) {
- case(Item::FIELD_ITEM): {
+ {
+ switch (item->type()) {
+ case Item::FIELD_ITEM:
+ {
Item_field *field_item= (Item_field *) item;
Field *field= field_item->field;
enum_field_types type= field->type();
@@ -6389,23 +6375,23 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::INT_ITEM);
}
else
- switch(field->result_type()) {
- case(STRING_RESULT):
+ switch (field->result_type()) {
+ case STRING_RESULT:
// Expect char string or binary string
context->expect_only(Item::STRING_ITEM);
context->expect(Item::VARBIN_ITEM);
context->expect_collation(field_item->collation.collation);
break;
- case(REAL_RESULT):
+ case REAL_RESULT:
context->expect_only(Item::REAL_ITEM);
context->expect(Item::DECIMAL_ITEM);
context->expect(Item::INT_ITEM);
break;
- case(INT_RESULT):
+ case INT_RESULT:
context->expect_only(Item::INT_ITEM);
context->expect(Item::VARBIN_ITEM);
break;
- case(DECIMAL_RESULT):
+ case DECIMAL_RESULT:
context->expect_only(Item::DECIMAL_ITEM);
context->expect(Item::REAL_ITEM);
context->expect(Item::INT_ITEM);
@@ -6450,7 +6436,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
break;
}
- case(Item::FUNC_ITEM): {
+ case Item::FUNC_ITEM:
+ {
Item_func *func_item= (Item_func *) item;
// Check that we expect a function or functional expression here
if (context->expecting(Item::FUNC_ITEM) ||
@@ -6463,8 +6450,9 @@ void ndb_serialize_cond(const Item *item, void *arg)
break;
}
- switch(func_item->functype()) {
- case(Item_func::EQ_FUNC): {
+ switch (func_item->functype()) {
+ case Item_func::EQ_FUNC:
+ {
DBUG_PRINT("info", ("EQ_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6480,7 +6468,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::NE_FUNC): {
+ case Item_func::NE_FUNC:
+ {
DBUG_PRINT("info", ("NE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6496,7 +6485,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::LT_FUNC): {
+ case Item_func::LT_FUNC:
+ {
DBUG_PRINT("info", ("LT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6512,7 +6502,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::LE_FUNC): {
+ case Item_func::LE_FUNC:
+ {
DBUG_PRINT("info", ("LE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6528,7 +6519,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::GE_FUNC): {
+ case Item_func::GE_FUNC:
+ {
DBUG_PRINT("info", ("GE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6544,7 +6536,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::GT_FUNC): {
+ case Item_func::GT_FUNC:
+ {
DBUG_PRINT("info", ("GT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6560,7 +6553,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::LIKE_FUNC): {
+ case Item_func::LIKE_FUNC:
+ {
DBUG_PRINT("info", ("LIKE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6570,7 +6564,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::FUNC_ITEM);
break;
}
- case(Item_func::NOTLIKE_FUNC): {
+ case Item_func::NOTLIKE_FUNC:
+ {
DBUG_PRINT("info", ("NOTLIKE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6580,7 +6575,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::FUNC_ITEM);
break;
}
- case(Item_func::ISNULL_FUNC): {
+ case Item_func::ISNULL_FUNC:
+ {
DBUG_PRINT("info", ("ISNULL_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6591,7 +6587,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::ISNOTNULL_FUNC): {
+ case Item_func::ISNOTNULL_FUNC:
+ {
DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6602,7 +6599,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
break;
}
- case(Item_func::NOT_FUNC): {
+ case Item_func::NOT_FUNC:
+ {
DBUG_PRINT("info", ("NOT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
@@ -6610,7 +6608,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::COND_ITEM);
break;
}
- case(Item_func::BETWEEN) : {
+ case Item_func::BETWEEN:
+ {
DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
Ndb_rewrite_context *rewrite_context=
new Ndb_rewrite_context(func_item);
@@ -6626,7 +6625,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::FUNC_ITEM);
break;
}
- case(Item_func::IN_FUNC) : {
+ case Item_func::IN_FUNC:
+ {
DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
Ndb_rewrite_context *rewrite_context=
new Ndb_rewrite_context(func_item);
@@ -6642,13 +6642,16 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect(Item::FUNC_ITEM);
break;
}
- case(Item_func::UNKNOWN_FUNC): {
+ case Item_func::UNKNOWN_FUNC:
+ {
DBUG_PRINT("info", ("UNKNOWN_FUNC %s",
func_item->const_item()?"const":""));
DBUG_PRINT("info", ("result type %d", func_item->result_type()));
if (func_item->const_item())
- switch(func_item->result_type()) {
- case(STRING_RESULT): {
+ {
+ switch (func_item->result_type()) {
+ case STRING_RESULT:
+ {
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::STRING_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -6677,7 +6680,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->skip= func_item->argument_count();
break;
}
- case(REAL_RESULT): {
+ case REAL_RESULT:
+ {
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::REAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -6699,7 +6703,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->skip= func_item->argument_count();
break;
}
- case(INT_RESULT): {
+ case INT_RESULT:
+ {
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::INT_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -6721,7 +6726,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->skip= func_item->argument_count();
break;
}
- case(DECIMAL_RESULT): {
+ case DECIMAL_RESULT:
+ {
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::DECIMAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -6745,12 +6751,14 @@ void ndb_serialize_cond(const Item *item, void *arg)
default:
break;
}
+ }
else
// Function does not return constant expression
context->supported= FALSE;
break;
}
- default: {
+ default:
+ {
DBUG_PRINT("info", ("Found func_item of type %d",
func_item->functype()));
context->supported= FALSE;
@@ -6758,7 +6766,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
break;
}
- case(Item::STRING_ITEM):
+ case Item::STRING_ITEM:
DBUG_PRINT("info", ("STRING_ITEM"));
if (context->expecting(Item::STRING_ITEM))
{
@@ -6797,7 +6805,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
else
context->supported= FALSE;
break;
- case(Item::INT_ITEM):
+ case Item::INT_ITEM:
DBUG_PRINT("info", ("INT_ITEM"));
if (context->expecting(Item::INT_ITEM))
{
@@ -6824,7 +6832,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
else
context->supported= FALSE;
break;
- case(Item::REAL_ITEM):
+ case Item::REAL_ITEM:
DBUG_PRINT("info", ("REAL_ITEM %s"));
if (context->expecting(Item::REAL_ITEM))
{
@@ -6849,7 +6857,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
else
context->supported= FALSE;
break;
- case(Item::VARBIN_ITEM):
+ case Item::VARBIN_ITEM:
DBUG_PRINT("info", ("VARBIN_ITEM"));
if (context->expecting(Item::VARBIN_ITEM))
{
@@ -6872,7 +6880,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
else
context->supported= FALSE;
break;
- case(Item::DECIMAL_ITEM):
+ case Item::DECIMAL_ITEM:
DBUG_PRINT("info", ("DECIMAL_ITEM %s"));
if (context->expecting(Item::DECIMAL_ITEM))
{
@@ -6898,17 +6906,19 @@ void ndb_serialize_cond(const Item *item, void *arg)
else
context->supported= FALSE;
break;
- case(Item::COND_ITEM): {
+ case Item::COND_ITEM:
+ {
Item_cond *cond_item= (Item_cond *) item;
if (context->expecting(Item::COND_ITEM))
- switch(cond_item->functype()) {
- case(Item_func::COND_AND_FUNC):
+ {
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC:
DBUG_PRINT("info", ("COND_AND_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
cond_item);
break;
- case(Item_func::COND_OR_FUNC):
+ case Item_func::COND_OR_FUNC:
DBUG_PRINT("info", ("COND_OR_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
cond_item);
@@ -6918,17 +6928,21 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->supported= FALSE;
break;
}
+ }
else
- // Did not expect condition
+ {
+ /* Did not expect condition */
context->supported= FALSE;
+ }
break;
}
- default: {
+ default:
+ {
DBUG_PRINT("info", ("Found item of type %d", item->type()));
context->supported= FALSE;
}
}
-
+ }
if (context->supported && context->rewrite_stack)
{
Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
@@ -6972,18 +6986,19 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
bool negated)
{
DBUG_ENTER("build_scan_filter_predicate");
- switch(cond->ndb_item->type) {
- case(NDB_FUNCTION): {
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
if (!cond->next)
break;
Ndb_item *a= cond->next->ndb_item;
Ndb_item *b, *field, *value= NULL;
- switch(cond->ndb_item->argument_count()) {
- case(1):
+ switch (cond->ndb_item->argument_count()) {
+ case 1:
field=
(a->type == NDB_FIELD)? a : NULL;
break;
- case(2):
+ case 2:
if (!cond->next->next)
break;
b= cond->next->next->ndb_item;
@@ -6999,11 +7014,11 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
default:
break;
}
- switch((negated) ?
- Ndb_item::negate(cond->ndb_item->qualification.function_type)
- : cond->ndb_item->qualification.function_type)
+ switch ((negated) ?
+ Ndb_item::negate(cond->ndb_item->qualification.function_type)
+ : cond->ndb_item->qualification.function_type) {
+ case Item_func::EQ_FUNC:
{
- case(Item_func::EQ_FUNC): {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7016,7 +7031,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::NE_FUNC): {
+ case Item_func::NE_FUNC:
+ {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7029,7 +7045,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::LT_FUNC): {
+ case Item_func::LT_FUNC:
+ {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7054,7 +7071,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::LE_FUNC): {
+ case Item_func::LE_FUNC:
+ {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7079,7 +7097,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::GE_FUNC): {
+ case Item_func::GE_FUNC:
+ {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7104,7 +7123,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::GT_FUNC): {
+ case Item_func::GT_FUNC:
+ {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
@@ -7129,7 +7149,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::LIKE_FUNC): {
+ case Item_func::LIKE_FUNC:
+ {
if (!value || !field) break;
if ((value->qualification.value_type != Item::STRING_ITEM) &&
(value->qualification.value_type != Item::VARBIN_ITEM))
@@ -7147,7 +7168,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::NOTLIKE_FUNC): {
+ case Item_func::NOTLIKE_FUNC:
+ {
if (!value || !field) break;
if ((value->qualification.value_type != Item::STRING_ITEM) &&
(value->qualification.value_type != Item::VARBIN_ITEM))
@@ -7165,7 +7187,7 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
cond= cond->next->next->next;
DBUG_RETURN(0);
}
- case(Item_func::ISNULL_FUNC):
+ case Item_func::ISNULL_FUNC:
if (!field)
break;
DBUG_PRINT("info", ("Generating ISNULL filter"));
@@ -7173,7 +7195,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(1);
cond= cond->next->next;
DBUG_RETURN(0);
- case(Item_func::ISNOTNULL_FUNC): {
+ case Item_func::ISNOTNULL_FUNC:
+ {
if (!field)
break;
DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
@@ -7199,15 +7222,18 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
{
uint level=0;
bool negated= FALSE;
-
DBUG_ENTER("build_scan_filter_group");
+
do
{
- if (!cond) DBUG_RETURN(1);
- switch(cond->ndb_item->type) {
- case(NDB_FUNCTION):
- switch(cond->ndb_item->qualification.function_type) {
- case(Item_func::COND_AND_FUNC): {
+ if (!cond)
+ DBUG_RETURN(1);
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
+ switch (cond->ndb_item->qualification.function_type) {
+ case Item_func::COND_AND_FUNC:
+ {
level++;
DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
level));
@@ -7218,7 +7244,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
cond= cond->next;
break;
}
- case(Item_func::COND_OR_FUNC): {
+ case Item_func::COND_OR_FUNC:
+ {
level++;
DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
level));
@@ -7229,11 +7256,11 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
cond= cond->next;
break;
}
- case(Item_func::NOT_FUNC): {
+ case Item_func::NOT_FUNC:
+ {
DBUG_PRINT("info", ("Generating negated query"));
cond= cond->next;
negated= TRUE;
-
break;
}
default:
@@ -7243,7 +7270,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
break;
}
break;
- case(NDB_END_COND):
+ }
+ case NDB_END_COND:
DBUG_PRINT("info", ("End of group %u", level));
level--;
if (cond) cond= cond->next;
@@ -7252,7 +7280,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
if (!negated)
break;
// else fall through (NOT END is an illegal condition)
- default: {
+ default:
+ {
DBUG_PRINT("info", ("Illegal scan filter"));
}
}
@@ -7267,11 +7296,11 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
bool simple_cond= TRUE;
DBUG_ENTER("build_scan_filter");
- switch(cond->ndb_item->type) {
- case(NDB_FUNCTION):
- switch(cond->ndb_item->qualification.function_type) {
- case(Item_func::COND_AND_FUNC):
- case(Item_func::COND_OR_FUNC):
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ switch (cond->ndb_item->qualification.function_type) {
+ case Item_func::COND_AND_FUNC:
+ case Item_func::COND_OR_FUNC:
simple_cond= FALSE;
break;
default:
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 9ea32e61190..b34f8dd063c 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -551,7 +551,7 @@ private:
int pk_read(const byte *key, uint key_len, byte *buf);
int complemented_pk_read(const byte *old_data, byte *new_data);
- int peek_row();
+ int peek_row(const byte *record);
int unique_index_read(const byte *key, uint key_len,
byte *buf);
int ordered_index_scan(const key_range *start_key,
@@ -580,8 +580,7 @@ private:
friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
int get_ndb_blobs_value(NdbBlob *last_ndb_blob);
int set_primary_key(NdbOperation *op, const byte *key);
- int set_primary_key(NdbOperation *op);
- int set_primary_key_from_old_data(NdbOperation *op, const byte *old_data);
+ int set_primary_key_from_record(NdbOperation *op, const byte *record);
int set_bounds(NdbIndexScanOperation*, const key_range *keys[2], uint= 0);
int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
int set_index_key(NdbOperation *, const KEY *key_info, const byte *key_ptr);
@@ -681,7 +680,8 @@ int ndbcluster_discover(THD* thd, const char* dbname, const char* name,
const void** frmblob, uint* frmlen);
int ndbcluster_find_files(THD *thd,const char *db,const char *path,
const char *wild, bool dir, List<char> *files);
-int ndbcluster_table_exists(THD* thd, const char *db, const char *name);
+int ndbcluster_table_exists_in_engine(THD* thd,
+ const char *db, const char *name);
int ndbcluster_drop_database(const char* path);
void ndbcluster_print_error(int error, const NdbOperation *error_op);
diff --git a/sql/handler.cc b/sql/handler.cc
index 1973cd71d46..a61dce35501 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -165,12 +165,22 @@ my_bool ha_storage_engine_is_enabled(enum db_type database_type)
/* Use other database handler if databasehandler is not incompiled */
-enum db_type ha_checktype(enum db_type database_type)
+enum db_type ha_checktype(THD *thd, enum db_type database_type,
+ bool no_substitute, bool report_error)
{
- THD *thd;
if (ha_storage_engine_is_enabled(database_type))
return database_type;
+ if (no_substitute)
+ {
+ if (report_error)
+ {
+ const char *engine_name= ha_get_storage_engine(database_type);
+ my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
+ }
+ return DB_TYPE_UNKNOWN;
+ }
+
switch (database_type) {
#ifndef NO_HASH
case DB_TYPE_HASH:
@@ -182,7 +192,6 @@ enum db_type ha_checktype(enum db_type database_type)
break;
}
- thd= current_thd;
return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ?
(enum db_type) thd->variables.table_type :
((enum db_type) global_system_variables.table_type !=
@@ -1919,21 +1928,19 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
}
/*
- Try to discover table from engine and
+ Try to discover table from engine and
if found, write the frm file to disk.
-
+
RETURN VALUES:
- 0 : Table existed in engine and created
- on disk if so requested
- 1 : Table does not exist
- >1 : error
+ -1 : Table did not exists
+ 0 : Table created ok
+ > 0 : Error, table existed but could not be created
*/
-int ha_create_table_from_engine(THD* thd,
- const char *db,
- const char *name,
- bool create_if_found)
+int ha_create_table_from_engine(THD* thd,
+ const char *db,
+ const char *name)
{
int error;
const void *frmblob;
@@ -1942,45 +1949,43 @@ int ha_create_table_from_engine(THD* thd,
HA_CREATE_INFO create_info;
TABLE table;
DBUG_ENTER("ha_create_table_from_engine");
- DBUG_PRINT("enter", ("name '%s'.'%s' create_if_found: %d",
- db, name, create_if_found));
+ DBUG_PRINT("enter", ("name '%s'.'%s'", db, name));
bzero((char*) &create_info,sizeof(create_info));
-
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
- DBUG_RETURN(error);
+ {
+ /* Table could not be discovered and thus not created */
+ DBUG_RETURN(error);
+ }
+
/*
- Table exists in handler
- frmblob and frmlen are set
+ Table exists in handler and could be discovered
+ frmblob and frmlen are set, write the frm to disk
*/
- if (create_if_found)
- {
- (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS);
- // Save the frm file
- if ((error = writefrm(path, frmblob, frmlen)))
- goto err_end;
+ (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS);
+ // Save the frm file
+ error= writefrm(path, frmblob, frmlen);
+ my_free((char*) frmblob, MYF(0));
+ if (error)
+ DBUG_RETURN(2);
- if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table))
- DBUG_RETURN(1);
+ if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table))
+ DBUG_RETURN(3);
- update_create_info_from_table(&create_info, &table);
- create_info.table_options|= HA_CREATE_FROM_ENGINE;
+ update_create_info_from_table(&create_info, &table);
+ create_info.table_options|= HA_CREATE_FROM_ENGINE;
- if (lower_case_table_names == 2 &&
- !(table.file->table_flags() & HA_FILE_BASED))
- {
- /* Ensure that handler gets name in lower case */
- my_casedn_str(files_charset_info, path);
- }
-
- error=table.file->create(path,&table,&create_info);
- VOID(closefrm(&table));
+ if (lower_case_table_names == 2 &&
+ !(table.file->table_flags() & HA_FILE_BASED))
+ {
+ /* Ensure that handler gets name in lower case */
+ my_casedn_str(files_charset_info, path);
}
+ error=table.file->create(path,&table,&create_info);
+ VOID(closefrm(&table));
-err_end:
- my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR));
- DBUG_RETURN(error);
+ DBUG_RETURN(error != 0);
}
void st_ha_check_opt::init()
@@ -2083,14 +2088,15 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
Try to discover one table from handler(s)
RETURN
- 0 ok. In this case *frmblob and *frmlen are set
- 1 error. frmblob and frmlen may not be set
+ -1 : Table did not exists
+ 0 : OK. In this case *frmblob and *frmlen are set
+ >0 : error. frmblob and frmlen may not be set
*/
int ha_discover(THD *thd, const char *db, const char *name,
const void **frmblob, uint *frmlen)
{
- int error= 1; // Table does not exist in any handler
+ int error= -1; // Table does not exist in any handler
DBUG_ENTER("ha_discover");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
#ifdef HAVE_NDBCLUSTER_DB
@@ -2122,11 +2128,8 @@ ha_find_files(THD *thd,const char *db,const char *path,
error= ndbcluster_find_files(thd, db, path, wild, dir, files);
#endif
DBUG_RETURN(error);
-
-
}
-#ifdef NOT_YET_USED
/*
Ask handler if the table exists in engine
@@ -2137,20 +2140,19 @@ ha_find_files(THD *thd,const char *db,const char *path,
# Error code
*/
-int ha_table_exists(THD* thd, const char* db, const char* name)
+int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
{
- int error= 2;
- DBUG_ENTER("ha_table_exists");
+ int error= 0;
+ DBUG_ENTER("ha_table_exists_in_engine");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
#ifdef HAVE_NDBCLUSTER_DB
if (have_ndbcluster == SHOW_OPTION_YES)
- error= ndbcluster_table_exists(thd, db, name);
+ error= ndbcluster_table_exists_in_engine(thd, db, name);
#endif
+ DBUG_PRINT("exit", ("error: %d", error));
DBUG_RETURN(error);
}
-#endif
-
/*
Read the first row of a multi-range set.
diff --git a/sql/handler.h b/sql/handler.h
index 3b0b9afe320..df906e284e7 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -813,7 +813,8 @@ extern ulong total_ha, total_ha_2pc;
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
-enum db_type ha_checktype(enum db_type database_type);
+enum db_type ha_checktype(THD *thd, enum db_type database_type,
+ bool no_substitute, bool report_error);
/* basic stuff */
int ha_init(void);
@@ -830,13 +831,12 @@ int ha_delete_table(THD *thd, enum db_type db_type, const char *path,
const char *alias, bool generate_warning);
/* discovery */
-int ha_create_table_from_engine(THD* thd, const char *db, const char *name,
- bool create_if_found);
+int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
int ha_discover(THD* thd, const char* dbname, const char* name,
const void** frmblob, uint* frmlen);
int ha_find_files(THD *thd,const char *db,const char *path,
const char *wild, bool dir,List<char>* files);
-int ha_table_exists(THD* thd, const char* db, const char* name);
+int ha_table_exists_in_engine(THD* thd, const char* db, const char* name);
/* key cache */
int ha_init_key_cache(const char *name, KEY_CACHE *key_cache);
diff --git a/sql/item.cc b/sql/item.cc
index e7feeaa4289..d26e4ba7c20 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -314,6 +314,7 @@ void *Item::operator new(size_t size, Item *reuse, uint *rsize)
Item::Item():
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
+ is_autogenerated_name(TRUE),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
{
marker= 0;
@@ -437,16 +438,17 @@ void Item::rename(char *new_name)
}
-Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
- const char *field_name_par)
- :orig_db_name(db_name_par), orig_table_name(table_name_par),
- orig_field_name(field_name_par),
- db_name(db_name_par), table_name(table_name_par),
- field_name(field_name_par),
+Item_ident::Item_ident(Name_resolution_context *context_arg,
+ const char *db_name_arg,const char *table_name_arg,
+ const char *field_name_arg)
+ :orig_db_name(db_name_arg), orig_table_name(table_name_arg),
+ orig_field_name(field_name_arg), context(context_arg),
+ db_name(db_name_arg), table_name(table_name_arg),
+ field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0)
{
- name = (char*) field_name_par;
+ name = (char*) field_name_arg;
}
@@ -457,6 +459,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
orig_db_name(item->orig_db_name),
orig_table_name(item->orig_table_name),
orig_field_name(item->orig_field_name),
+ context(item->context),
db_name(item->db_name),
table_name(item->table_name),
field_name(item->field_name),
@@ -598,15 +601,75 @@ bool Item::eq(const Item *item, bool binary_cmp) const
Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
{
/*
+ Allow conversion from and to "binary".
Don't allow automatic conversion to non-Unicode charsets,
as it potentially loses data.
*/
- if (!(tocs->state & MY_CS_UNICODE))
+ if (collation.collation != &my_charset_bin &&
+ tocs != &my_charset_bin &&
+ !(tocs->state & MY_CS_UNICODE))
return NULL; // safe conversion is not possible
return new Item_func_conv_charset(this, tocs);
}
+/*
+ Created mostly for mysql_prepare_table(). Important
+ when a string ENUM/SET column is described with a numeric default value:
+
+ CREATE TABLE t1(a SET('a') DEFAULT 1);
+
+ We cannot use generic Item::safe_charset_converter(), because
+ the latter returns a non-fixed Item, so val_str() crashes afterwards.
+ Override Item_num method, to return a fixed item.
+*/
+Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ char buf[64];
+ String *s, tmp(buf, sizeof(buf), &my_charset_bin);
+ s= val_str(&tmp);
+ if ((conv= new Item_string(s->ptr(), s->length(), s->charset())))
+ {
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ }
+ return conv;
+}
+
+
+Item *Item_static_int_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ char buf[64];
+ String *s, tmp(buf, sizeof(buf), &my_charset_bin);
+ s= val_str(&tmp);
+ if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
+ s->charset())))
+ {
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ }
+ return conv;
+}
+
+
+Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ char buf[64];
+ String *s, tmp(buf, sizeof(buf), &my_charset_bin);
+ s= val_str(&tmp);
+ if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
+ s->charset())))
+ {
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ }
+ return conv;
+}
+
+
Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
@@ -632,6 +695,33 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
}
+Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ uint conv_errors;
+ String tmp, cstr, *ostr= val_str(&tmp);
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
+ if (conv_errors ||
+ !(conv= new Item_static_string_func(func_name,
+ cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
+ {
+ /*
+ Safe conversion is not possible (or EOM).
+ We could not convert a string into the requested character set
+ without data loss. The target charset does not cover all the
+ characters from the string. Operation cannot be done correctly.
+ */
+ return NULL;
+ }
+ conv->str_value.copy();
+ /* Ensure that no one is going to change the result string */
+ conv->str_value.mark_as_const();
+ return conv;
+}
+
+
bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (type() == item->type() && item->basic_const_item())
@@ -782,7 +872,7 @@ Item_splocal::type() const
}
-bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **)
+bool Item_splocal::fix_fields(THD *, Item **)
{
Item *it= this_item();
DBUG_ASSERT(it->fixed);
@@ -852,7 +942,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
uint el= fields.elements;
Item *new_item;
ref_pointer_array[el]= this;
- if (!(new_item= new Item_ref(ref_pointer_array + el, 0, name)))
+ if (!(new_item= new Item_ref(&thd->lex->current_select->context,
+ ref_pointer_array + el, 0, name)))
return; // fatal_error is set
fields.push_front(this);
ref_pointer_array[el]= this;
@@ -992,7 +1083,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
}
Item_field::Item_field(Field *f)
- :Item_ident(NullS, *f->table_name, f->field_name),
+ :Item_ident(0, NullS, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
@@ -1004,8 +1095,9 @@ Item_field::Item_field(Field *f)
orig_table_name= orig_field_name= "";
}
-Item_field::Item_field(THD *thd, Field *f)
- :Item_ident(f->table->s->db, *f->table_name, f->field_name),
+Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
+ Field *f)
+ :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
@@ -1040,6 +1132,17 @@ Item_field::Item_field(THD *thd, Field *f)
set_field(f);
}
+
+Item_field::Item_field(Name_resolution_context *context_arg,
+ const char *db_arg,const char *table_name_arg,
+ const char *field_name_arg)
+ :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
+ field(0), result_field(0), item_equal(0), no_const_subst(0),
+ have_privileges(0), any_privileges(0)
+{
+ collation.set(DERIVATION_IMPLICIT);
+}
+
// Constructor need to process subselect with temporary tables (see Item)
Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
@@ -1685,6 +1788,7 @@ void Item_param::set_null()
max_length= 0;
decimals= 0;
state= NULL_VALUE;
+ item_type= Item::NULL_ITEM;
DBUG_VOID_RETURN;
}
@@ -1925,6 +2029,7 @@ void Item_param::reset()
to the binary log.
*/
str_value.set_charset(&my_charset_bin);
+ collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
state= NO_VALUE;
maybe_null= 1;
null_value= 0;
@@ -2226,37 +2331,12 @@ bool Item_param::convert_str_value(THD *thd)
*/
str_value_ptr.set(str_value.ptr(), str_value.length(),
str_value.charset());
+ /* Synchronize item charset with value charset */
+ collation.set(str_value.charset(), DERIVATION_COERCIBLE);
}
return rc;
}
-bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
-{
- DBUG_ASSERT(fixed == 0);
- SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select;
-
- /*
- Parameters in a subselect should mark the subselect as not constant
- during prepare
- */
- if (state == NO_VALUE)
- {
- /*
- SELECT_LEX_UNIT::item set only for subqueries, so test of it presence
- can be barrier to stop before derived table SELECT or very outer SELECT
- */
- for (; cursel->master_unit()->item;
- cursel= cursel->outer_select())
- {
- Item_subselect *subselect_item= cursel->master_unit()->item;
- subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
- subselect_item->const_item_cache= 0;
- }
- }
- fixed= 1;
- return 0;
-}
-
bool Item_param::basic_const_item() const
{
@@ -2390,9 +2470,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions)
*/
/* ARGSUSED */
-bool Item::fix_fields(THD *thd,
- struct st_table_list *list,
- Item ** ref)
+bool Item::fix_fields(THD *thd, Item ** ref)
{
// We do not check fields which are fixed during construction
@@ -2759,7 +2837,6 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
SYNOPSIS
Item_field::fix_fields()
thd [in] current thread
- tables [in] the tables in a FROM clause
reference [in/out] view column if this item was resolved to a view column
DESCRIPTION
@@ -2805,7 +2882,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
FALSE on success
*/
-bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
+bool Item_field::fix_fields(THD *thd, Item **reference)
{
enum_parsing_place place= NO_MATTER;
DBUG_ASSERT(fixed == 0);
@@ -2818,135 +2895,131 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, 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, tables, reference,
- IGNORE_EXCEPT_NON_UNIQUE,
- !any_privileges)) ==
+ if ((from_field= find_field_in_tables(thd, this, context->table_list,
+ reference,
+ IGNORE_EXCEPT_NON_UNIQUE,
+ !any_privileges &&
+ context->check_privileges,
+ TRUE)) ==
not_found_field)
{
- SELECT_LEX *last= 0;
- TABLE_LIST *table_list;
- Item **ref= (Item **) not_found_item;
- SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
/*
- If there is an outer select, and it is not a derived table (which do
- not support the use of outer fields for now), try to resolve this
- reference in the outer select(s).
-
+ If there is an 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.
+ searched starting from the innermost.
*/
- if (current_sel->master_unit()->first_select()->linkage !=
- DERIVED_TABLE_TYPE)
+ Name_resolution_context *last_checked_context= context;
+ Item **ref= (Item **) not_found_item;
+ Name_resolution_context *outer_context= context->outer_context;
+ for (;
+ outer_context;
+ outer_context= outer_context->outer_context)
{
- SELECT_LEX_UNIT *prev_unit= current_sel->master_unit();
- SELECT_LEX *outer_sel= prev_unit->outer_select();
- for ( ; outer_sel ;
- outer_sel= (prev_unit= outer_sel->master_unit())->outer_select())
- {
- last= outer_sel;
- Item_subselect *prev_subselect_item= prev_unit->item;
- upward_lookup= TRUE;
-
- /* Search in the tables of the FROM clause of the outer select. */
- table_list= outer_sel->get_table_list();
- if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
- {
- /*
- It is a primary INSERT st_select_lex => do not resolve against the
- first table.
- */
- table_list= table_list->next_local;
- }
- place= prev_subselect_item->parsing_place;
- /*
- Check table fields only if the subquery is used somewhere out of
- HAVING, or the outer SELECT does not use grouping (i.e. tables are
- accessible).
+ SELECT_LEX *select= outer_context->select_lex;
+ Item_subselect *prev_subselect_item=
+ last_checked_context->select_lex->master_unit()->item;
+ last_checked_context= outer_context;
+ upward_lookup= TRUE;
- In case of view, find_field_in_tables() write pointer to view
- field expression to 'reference', i.e. it substitute that
- expression instead of this Item_field
- */
- if ((place != IN_HAVING ||
- (outer_sel->with_sum_func == 0 &&
- outer_sel->group_list.elements == 0)) &&
- (from_field= find_field_in_tables(thd, this, table_list,
- reference,
- IGNORE_EXCEPT_NON_UNIQUE,
- TRUE)) !=
- not_found_field)
- {
- if (from_field)
- {
- if (from_field != view_ref_found)
- {
- prev_subselect_item->used_tables_cache|= from_field->table->map;
- prev_subselect_item->const_item_cache= 0;
- }
- else
- {
- Item::Type type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
- mark_as_dependent(thd, last, current_sel, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
- (Item_ident*) (*reference) :
- 0));
- /*
- view reference found, we substituted it instead of this
- Item (find_field_in_tables do it by assigning new value to
- *reference), so can quit
- */
- return FALSE;
- }
- }
- break;
- }
+ place= prev_subselect_item->parsing_place;
+ /*
+ Check table fields only if the subquery is used somewhere out of
+ HAVING, or the outer SELECT does not use grouping (i.e. tables are
+ accessible).
- /* Search in the SELECT and GROUP lists of the outer select. */
- if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
+ In case of a view, find_field_in_tables() writes the pointer to
+ the found view field into '*reference', in other words, it
+ substitutes this Item_field with the found expression.
+ */
+ if ((place != IN_HAVING ||
+ (!select->with_sum_func &&
+ select->group_list.elements == 0)) &&
+ (from_field= find_field_in_tables(thd, this,
+ outer_context->table_list,
+ reference,
+ IGNORE_EXCEPT_NON_UNIQUE,
+ outer_context->
+ check_privileges,
+ TRUE)) !=
+ not_found_field)
+ {
+ if (from_field)
{
- if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occurred (e.g. ambiguous names). */
- if (ref != not_found_item)
+ if (from_field != view_ref_found)
{
- DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
- break;
+ prev_subselect_item->used_tables_cache|= from_field->table->map;
+ prev_subselect_item->const_item_cache= 0;
}
- }
+ else
+ {
+ Item::Type type= (*reference)->type();
+ prev_subselect_item->used_tables_cache|=
+ (*reference)->used_tables();
+ prev_subselect_item->const_item_cache&=
+ (*reference)->const_item();
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex, this,
+ ((type == REF_ITEM || type == FIELD_ITEM) ?
+ (Item_ident*) (*reference) :
+ 0));
+ /*
+ A reference to a view field had been found and we
+ substituted it instead of this Item (find_field_in_tables
+ does it by assigning the new value to *reference), so now
+ we can return from this function.
+ */
+ return FALSE;
+ }
+ }
+ break;
+ }
- // Reference is not found => depend from outer (or just error)
- prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
- prev_subselect_item->const_item_cache= 0;
+ /* Search in SELECT and GROUP lists of the outer select. */
+ if (outer_context->resolve_in_select_list)
+ {
+ if (!(ref= resolve_ref_in_select_and_group(thd, this, select)))
+ goto error; /* Some error occurred (e.g. ambiguous names). */
+ if (ref != not_found_item)
+ {
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
+ prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ break;
+ }
+ }
- if (outer_sel->master_unit()->first_select()->linkage ==
- DERIVED_TABLE_TYPE)
- break; // do not look over derived table
- }
+ /*
+ Reference is not found in this select => this subquery depend on
+ outer select (or we just trying to find wrong identifier, in this
+ case it does not matter which used tables bits we set)
+ */
+ prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
+ prev_subselect_item->const_item_cache= 0;
}
DBUG_ASSERT(ref != 0);
if (!from_field)
- return TRUE;
+ goto error;
if (ref == not_found_item && from_field == not_found_field)
{
if (upward_lookup)
{
- // We can't say exactly what absent table or field
+ // We can't say exactly what absent table or field
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
}
else
{
- // Call to report error
- find_field_in_tables(thd, this, tables, reference, REPORT_ALL_ERRORS,
- TRUE);
+ /* Call find_field_in_tables only to report the error */
+ find_field_in_tables(thd, this, context->table_list,
+ reference, REPORT_ALL_ERRORS,
+ !any_privileges &&
+ context->check_privileges, TRUE);
}
- return TRUE;
+ goto error;
}
else if (ref != not_found_item)
{
@@ -2964,45 +3037,54 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
save= *ref;
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
- new Item_ref(ref, (char*) table_name, (char*) field_name) :
- new Item_direct_ref(ref, (char*) table_name, (char*) field_name));
+ new Item_ref(context, ref, (char*) table_name,
+ (char*) field_name) :
+ new Item_direct_ref(context, ref, (char*) table_name,
+ (char*) field_name));
*ref= save;
if (!rf)
- return TRUE;
+ goto error;
thd->change_item_tree(reference, rf);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT(!rf->fixed); // Assured by Item_ref()
- if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
- return TRUE;
+ if (rf->fix_fields(thd, reference) || rf->check_cols(1))
+ goto error;
- mark_as_dependent(thd, last, current_sel, this, rf);
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex, this,
+ rf);
return FALSE;
}
else
{
- mark_as_dependent(thd, last, current_sel, this, this);
- if (last->having_fix_field)
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex,
+ this, this);
+ if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
- rf= new Item_ref((cached_table->db[0] ? cached_table->db : 0),
+ rf= new Item_ref(context,
+ (cached_table->db[0] ? cached_table->db : 0),
(char*) cached_table->alias, (char*) field_name);
if (!rf)
- return TRUE;
+ goto error;
thd->change_item_tree(reference, rf);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT(!rf->fixed); // Assured by Item_ref()
- return (rf->fix_fields(thd, tables, reference) || rf->check_cols(1));
+ if (rf->fix_fields(thd, reference) || rf->check_cols(1))
+ goto error;
+ return FALSE;
}
}
}
else if (!from_field)
- return TRUE;
+ goto error;
/*
if it is not expression from merged VIEW we will set this field.
@@ -3050,12 +3132,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->priv_user, thd->host_or_ip,
field_name, tab);
- return TRUE;
+ goto error;
}
}
#endif
fixed= 1;
return FALSE;
+
+error:
+ context->process_error(thd);
+ return TRUE;
}
@@ -3344,6 +3430,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_YEAR:
return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table);
+ case MYSQL_TYPE_BIT:
+ return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0,
+ Field::NONE, name, table);
default:
/* This case should never be chosen */
DBUG_ASSERT(0);
@@ -3570,7 +3659,7 @@ Item *Item_int_with_ref::new_item()
Item_num *Item_uint::neg()
{
- Item_decimal *item= new Item_decimal(value, 0);
+ Item_decimal *item= new Item_decimal(value, 1);
return item->neg();
}
@@ -3752,6 +3841,20 @@ bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const
return FALSE;
}
+
+Item *Item_hex_string::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ String tmp, *str= val_str(&tmp);
+
+ if (!(conv= new Item_string(str->ptr(), str->length(), tocs)))
+ return NULL;
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ return conv;
+}
+
+
/*
bin item.
In string context this is a binary string.
@@ -3916,16 +4019,17 @@ bool Item_field::send(Protocol *protocol, String *buffer)
}
-Item_ref::Item_ref(Item **item, const char *table_name_par,
- const char *field_name_par)
- :Item_ident(NullS, table_name_par, field_name_par), result_field(0),
- ref(item)
+Item_ref::Item_ref(Name_resolution_context *context_arg,
+ Item **item, const char *table_name_arg,
+ const char *field_name_arg)
+ :Item_ident(context_arg, NullS, table_name_arg, field_name_arg),
+ result_field(0), ref(item)
{
/*
This constructor used to create some internals references over fixed items
*/
DBUG_ASSERT(ref != 0);
- if (*ref)
+ if (*ref && (*ref)->fixed)
set_properties();
}
@@ -3936,7 +4040,6 @@ Item_ref::Item_ref(Item **item, const char *table_name_par,
SYNOPSIS
Item_ref::fix_fields()
thd [in] current thread
- tables [in] the tables in a FROM clause
reference [in/out] view column if this item was resolved to a view column
DESCRIPTION
@@ -3988,59 +4091,56 @@ Item_ref::Item_ref(Item **item, const char *table_name_par,
FALSE on success
*/
-bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
+bool Item_ref::fix_fields(THD *thd, Item **reference)
{
- DBUG_ASSERT(fixed == 0);
enum_parsing_place place= NO_MATTER;
+ DBUG_ASSERT(fixed == 0);
SELECT_LEX *current_sel= thd->lex->current_select;
if (!ref || ref == not_found_item)
{
- SELECT_LEX_UNIT *prev_unit= current_sel->master_unit();
- SELECT_LEX *outer_sel= prev_unit->outer_select();
-
- if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel)))
- return TRUE; /* Some error occurred (e.g. ambiguous names). */
+ if (!(ref= resolve_ref_in_select_and_group(thd, this,
+ context->select_lex)))
+ goto error; /* Some error occurred (e.g. ambiguous names). */
if (ref == not_found_item) /* This reference was not resolved. */
{
- TABLE_LIST *table_list;
+ Name_resolution_context *last_checked_context= context;
+ Name_resolution_context *outer_context= context->outer_context;
Field *from_field;
- SELECT_LEX *last;
ref= 0;
- if (!outer_sel || (current_sel->master_unit()->first_select()->linkage ==
- DERIVED_TABLE_TYPE))
+ if (!outer_context)
{
/* The current reference cannot be resolved in this query. */
my_error(ER_BAD_FIELD_ERROR,MYF(0),
this->full_name(), current_thd->where);
- return TRUE;
+ goto error;
}
+
/*
- If there is an outer select, and it is not a derived table (which do
- not support the use of outer fields for now), try to resolve this
- reference in the outer select(s).
+ If there is an outer context (select), and it is not a derived table
+ (which do not support the use of outer fields for now), try to
+ resolve this reference in the outer select(s).
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.
*/
from_field= (Field*) not_found_field;
- last= 0;
- /* The following loop will always be excuted at least once */
- for ( ; outer_sel ;
- outer_sel= (prev_unit= outer_sel->master_unit())->outer_select())
+ do
{
- last= outer_sel;
- Item_subselect *prev_subselect_item= prev_unit->item;
+ SELECT_LEX *select= outer_context->select_lex;
+ Item_subselect *prev_subselect_item=
+ last_checked_context->select_lex->master_unit()->item;
+ last_checked_context= outer_context;
/* Search in the SELECT and GROUP lists of the outer select. */
- if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
+ if (outer_context->resolve_in_select_list)
{
- if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occurred (e.g. ambiguous names). */
+ if (!(ref= resolve_ref_in_select_and_group(thd, this, select)))
+ goto error; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
@@ -4056,43 +4156,34 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
ref= 0;
}
- /* Search in the tables of the FROM clause of the outer select. */
- table_list= outer_sel->get_table_list();
- if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
- {
- /*
- It is a primary INSERT st_select_lex => do not resolve against
- the first table.
- */
- table_list= table_list->next_local;
- }
-
place= prev_subselect_item->parsing_place;
/*
Check table fields only if the subquery is used somewhere out of
HAVING or the outer SELECT does not use grouping (i.e. tables are
accessible).
- TODO:
+ TODO:
Here we could first find the field anyway, and then test this
condition, so that we can give a better error message -
ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
ER_BAD_FIELD_ERROR which we produce now.
*/
if ((place != IN_HAVING ||
- (!outer_sel->with_sum_func &&
- outer_sel->group_list.elements == 0)))
+ (!select->with_sum_func &&
+ select->group_list.elements == 0)))
{
/*
In case of view, find_field_in_tables() write pointer to view
field expression to 'reference', i.e. it substitute that
expression instead of this Item_ref
*/
- from_field= find_field_in_tables(thd, this, table_list,
+ from_field= find_field_in_tables(thd, this,
+ outer_context->table_list,
reference,
IGNORE_EXCEPT_NON_UNIQUE,
+ outer_context->check_privileges,
TRUE);
if (! from_field)
- return TRUE;
+ goto error;
if (from_field == view_ref_found)
{
Item::Type type= (*reference)->type();
@@ -4101,7 +4192,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
prev_subselect_item->const_item_cache&=
(*reference)->const_item();
DBUG_ASSERT((*reference)->type() == REF_ITEM);
- mark_as_dependent(thd, last, current_sel, this,
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex, this,
((type == REF_ITEM || type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
@@ -4124,19 +4216,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0;
- if (outer_sel->master_unit()->first_select()->linkage ==
- DERIVED_TABLE_TYPE)
- break; /* Do not consider derived tables. */
- }
+ outer_context= outer_context->outer_context;
+ } while (outer_context);
DBUG_ASSERT(from_field != 0 && from_field != view_ref_found);
if (from_field != not_found_field)
{
Item_field* fld;
if (!(fld= new Item_field(from_field)))
- return TRUE;
+ goto error;
thd->change_item_tree(reference, fld);
- mark_as_dependent(thd, last, thd->lex->current_select, this, fld);
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ thd->lex->current_select, this, fld);
return FALSE;
}
if (ref == 0)
@@ -4144,11 +4235,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
/* The item was not a table field and not a reference */
my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), current_thd->where);
- return TRUE;
+ goto error;
}
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
- mark_as_dependent(thd, last, current_sel, this, this);
+ mark_as_dependent(thd, last_checked_context->select_lex,
+ context->select_lex, this, this);
}
}
@@ -4168,14 +4260,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
name, ((*ref)->with_sum_func?
"reference to group function":
"forward reference in item list"));
- return TRUE;
+ goto error;
}
set_properties();
if ((*ref)->check_cols(1))
- return TRUE;
+ goto error;
return FALSE;
+
+error:
+ context->process_error(thd);
+ return TRUE;
}
@@ -4360,6 +4456,39 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
return val;
}
+int Item_ref::save_in_field(Field *to, bool no_conversions)
+{
+ int res;
+ if (result_field)
+ {
+ if (result_field->is_null())
+ {
+ null_value= 1;
+ return set_field_to_null_with_conversions(to, no_conversions);
+ }
+ to->set_notnull();
+ field_conv(to, result_field);
+ null_value= 0;
+ return 0;
+ }
+ res= (*ref)->save_in_field(to, no_conversions);
+ null_value= (*ref)->null_value;
+ return res;
+}
+
+
+void Item_ref::make_field(Send_field *field)
+{
+ (*ref)->make_field(field);
+ /* Non-zero in case of a view */
+ if (name)
+ field->col_name= name;
+ if (table_name)
+ field->table_name= table_name;
+ if (db_name)
+ field->db_name= db_name;
+}
+
void Item_ref_null_helper::print(String *str)
{
@@ -4424,6 +4553,60 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
}
+/*
+ Prepare referenced view viewld then call usual Item_direct_ref::fix_fields
+
+ SYNOPSIS
+ Item_direct_view_ref::fix_fields()
+ thd thread handler
+ reference reference on reference where this item stored
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
+{
+ /* view fild reference must be defined */
+ DBUG_ASSERT(*ref);
+ /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */
+ if (!(*ref)->fixed &&
+ ((*ref)->fix_fields(thd, ref)))
+ return TRUE;
+ return Item_direct_ref::fix_fields(thd, reference);
+}
+
+/*
+ Compare view field's name with item's name before call to referenced
+ item's eq()
+
+ SYNOPSIS
+ Item_direct_view_ref::eq()
+ item item to compare with
+ binary_cmp make binary comparison
+
+ DESCRIPTION
+ Consider queries:
+ create view v1 as select t1.f1 as f2, t1.f2 as f1 from t1;
+ select * from v1 order by f1;
+ In order to choose right field for sorting we need to compare
+ given item's name (f1) to view field's name prior to calling
+ referenced item's eq().
+
+ RETURN
+ TRUE Referenced item is equal to given item
+ FALSE otherwise
+*/
+
+
+bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const
+{
+ Item *it= ((Item *) item)->real_item();
+ return (!it->name || !my_strcasecmp(system_charset_info, it->name,
+ field_name)) && ref && (*ref)->real_item()->eq(it, binary_cmp);
+}
+
void Item_null_helper::print(String *str)
{
str->append("<null_helper>(", 14);
@@ -4439,9 +4622,7 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const
}
-bool Item_default_value::fix_fields(THD *thd,
- struct st_table_list *table_list,
- Item **items)
+bool Item_default_value::fix_fields(THD *thd, Item **items)
{
Item *real_arg;
Item_field *field_arg;
@@ -4453,29 +4634,34 @@ bool Item_default_value::fix_fields(THD *thd,
fixed= 1;
return FALSE;
}
- if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
- return TRUE;
+ if (!arg->fixed && arg->fix_fields(thd, &arg))
+ goto error;
+
real_arg= arg->real_item();
if (real_arg->type() != FIELD_ITEM)
{
my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
- return TRUE;
+ goto error;
}
field_arg= (Item_field *)real_arg;
if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG)
{
my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
- return TRUE;
+ goto error;
}
if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of())))
- return TRUE;
+ goto error;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
def_field->move_field(def_field->table->s->default_values -
def_field->table->record[0]);
set_field(def_field);
return FALSE;
+
+error:
+ context->process_error(thd);
+ return TRUE;
}
@@ -4498,11 +4684,27 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
if (field_arg->flags & NO_DEFAULT_VALUE_FLAG)
{
- push_warning_printf(field_arg->table->in_use,
- MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_NO_DEFAULT_FOR_FIELD,
- ER(ER_NO_DEFAULT_FOR_FIELD),
- field_arg->field_name);
+ if (context->error_processor == &view_error_processor)
+ {
+ TABLE_LIST *view= (cached_table->belong_to_view ?
+ cached_table->belong_to_view :
+ cached_table);
+ // TODO: make correct error message
+ push_warning_printf(field_arg->table->in_use,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_DEFAULT_FOR_VIEW_FIELD,
+ ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
+ view->view_db.str,
+ view->view_name.str);
+ }
+ else
+ {
+ push_warning_printf(field_arg->table->in_use,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_DEFAULT_FOR_FIELD,
+ ER(ER_NO_DEFAULT_FOR_FIELD),
+ field_arg->field_name);
+ }
return 1;
}
field_arg->set_default();
@@ -4519,12 +4721,10 @@ bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
}
-bool Item_insert_value::fix_fields(THD *thd,
- struct st_table_list *table_list,
- Item **items)
+bool Item_insert_value::fix_fields(THD *thd, Item **items)
{
DBUG_ASSERT(fixed == 0);
- if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, &arg))
return TRUE;
if (arg->type() == REF_ITEM)
@@ -4613,9 +4813,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const
}
-bool Item_trigger_field::fix_fields(THD *thd,
- TABLE_LIST *table_list,
- Item **items)
+bool Item_trigger_field::fix_fields(THD *thd, Item **items)
{
/*
Since trigger is object tightly associated with TABLE object most
@@ -5128,8 +5326,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
acceptable information for client in send_field, so we make field
type from expression type.
*/
- switch (item->result_type())
- {
+ switch (item->result_type()) {
case STRING_RESULT:
return MYSQL_TYPE_VAR_STRING;
case INT_RESULT:
@@ -5331,9 +5528,13 @@ void Item_type_holder::get_full_info(Item *item)
if (fld_type == MYSQL_TYPE_ENUM ||
fld_type == MYSQL_TYPE_SET)
{
+ if (item->type() == Item::SUM_FUNC_ITEM &&
+ (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
+ ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC))
+ item = ((Item_sum*)item)->args[0];
/*
- We can have enum/set type after merging only if we have one enum/set
- field and number of NULL fields
+ We can have enum/set type after merging only if we have one enum|set
+ field (or MIN|MAX(enum|set field)) and number of NULL fields
*/
DBUG_ASSERT((enum_set_typelib &&
get_real_type(item) == MYSQL_TYPE_NULL) ||
@@ -5383,11 +5584,39 @@ void Item_result_field::cleanup()
DBUG_VOID_RETURN;
}
+/*
+ Dummy error processor used by default by Name_resolution_context
+
+ SYNOPSIS
+ dummy_error_processor()
+
+ NOTE
+ do nothing
+*/
+
+void dummy_error_processor(THD *thd, void *data)
+{}
+
+/*
+ Wrapper of hide_view_error call for Name_resolution_context error processor
+
+ SYNOPSIS
+ view_error_processor()
+
+ NOTE
+ hide view underlying tables details in error messages
+*/
+
+void view_error_processor(THD *thd, void *data)
+{
+ ((TABLE_LIST *)data)->hide_view_error(thd);
+}
+
/*****************************************************************************
** Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<Item>;
template class List_iterator<Item>;
template class List_iterator_fast<Item>;
diff --git a/sql/item.h b/sql/item.h
index 5ff2c726afd..f195557fb69 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -24,7 +24,6 @@ struct st_table_list;
void item_init(void); /* Init item functions */
class Item_field;
-
/*
"Declared Type Collation"
A combination of collation and its derivation.
@@ -218,18 +217,110 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits
static const Hybrid_type_traits_integer *instance();
};
+
+void dummy_error_processor(THD *thd, void *data);
+
+void view_error_processor(THD *thd, void *data);
+
+/*
+ Instances of Name_resolution_context store the information necesary for
+ name resolution of Items and other context analysis of a query made in
+ fix_fields().
+
+ This structure is a part of SELECT_LEX, a pointer to this structure is
+ assigned when an item is created (which happens mostly during parsing
+ (sql_yacc.yy)), but the structure itself will be initialized after parsing
+ is complete
+
+ TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to
+ separate SELECT_LEX which allow to remove tricks of changing this
+ structure before and after INSERT/CREATE and its SELECT to make correct
+ field name resolution.
+*/
+struct Name_resolution_context
+{
+ /*
+ The name resolution context to search in when an Item cannot be
+ resolved in this context (the context of an outer select)
+ */
+ Name_resolution_context *outer_context;
+
+ /*
+ List of tables used to resolve the items of this context. Usually these
+ are tables from the FROM clause of SELECT statement. The exceptions are
+ INSERT ... SELECT and CREATE ... SELECT statements, where SELECT
+ subquery is not moved to a separate SELECT_LEX. For these types of
+ statements we have to change this member dynamically to ensure correct
+ name resolution of different parts of the statement.
+ */
+ TABLE_LIST *table_list;
+
+ /*
+ SELECT_LEX item belong to, in case of merged VIEW it can differ from
+ SELECT_LEX where item was created, so we can't use table_list/field_list
+ from there
+ */
+ st_select_lex *select_lex;
+
+ /*
+ Processor of errors caused during Item name resolving, now used only to
+ hide underlying tables in errors about views (i.e. it substitute some
+ errors for views)
+ */
+ void (*error_processor)(THD *, void *);
+ void *error_processor_data;
+
+ /*
+ When TRUE items are resolved in this context both against the
+ SELECT list and this->table_list. If FALSE, items are resolved
+ only against this->table_list.
+ */
+ bool resolve_in_select_list;
+
+ /*
+ When FALSE we do not check columns right of resolving items, used to
+ prevent rights check on underlying tables of view
+ */
+ bool check_privileges;
+
+ Name_resolution_context()
+ :outer_context(0), table_list(0), select_lex(0),
+ error_processor_data(0),
+ check_privileges(TRUE)
+ {}
+
+ void init()
+ {
+ resolve_in_select_list= FALSE;
+ error_processor= &dummy_error_processor;
+ }
+
+ void resolve_in_table_list_only(TABLE_LIST *tables)
+ {
+ table_list= tables;
+ resolve_in_select_list= FALSE;
+ }
+
+ void process_error(THD *thd)
+ {
+ (*error_processor)(thd, error_processor_data);
+ }
+};
+
+
/*************************************************************************/
typedef bool (Item::*Item_processor)(byte *arg);
typedef Item* (Item::*Item_transformer) (byte *arg);
-
typedef void (*Cond_traverser) (const Item *item, void *arg);
+
class Item {
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
public:
- static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size)
+ { return (void*) sql_alloc((uint) size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
/* Special for SP local variable assignment - reusing slots */
@@ -243,7 +334,8 @@ public:
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
- PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM};
+ PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
+ VIEW_FIXER_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@@ -269,6 +361,8 @@ public:
my_bool unsigned_flag;
my_bool with_sum_func;
my_bool fixed; /* If item fixed with fix_fields */
+ my_bool is_autogenerated_name; /* indicate was name of this Item
+ autogenerated or set by user */
DTCollation collation;
// alloc & destruct is done as start of select using sql_alloc
@@ -288,13 +382,13 @@ public:
name=0;
#endif
} /*lint -e1509 */
- void set_name(const char *str,uint length, CHARSET_INFO *cs);
+ void set_name(const char *str, uint length, CHARSET_INFO *cs);
void rename(char *new_name);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup();
virtual void make_field(Send_field *field);
Field *make_string_field(TABLE *table);
- virtual bool fix_fields(THD *, struct st_table_list *, Item **);
+ virtual bool fix_fields(THD *, Item **);
/*
should be used in case where we are sure that we do not need
complete fix_fields() procedure.
@@ -468,6 +562,18 @@ public:
*/
virtual bool const_during_execution() const
{ return (used_tables() & ~PARAM_TABLE_BIT) == 0; }
+ /*
+ This is an essential method for correct functioning of VIEWS.
+ To save a view in an .frm file we need its unequivocal
+ definition in SQL that takes into account sql_mode and
+ environmental settings. Currently such definition is restored
+ by traversing through the parsed tree of a view and
+ print()'ing SQL syntax of every node to a String buffer. This
+ method is used to print the SQL definition of an item. The
+ second use of this method is for EXPLAIN EXTENDED, to print
+ the SQL of a query after all optimizations of the parsed tree
+ have been done.
+ */
virtual void print(String *str_arg) { str_arg->append(full_name()); }
void print_item_w_name(String *);
virtual void update_used_tables() {}
@@ -534,6 +640,9 @@ public:
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
virtual bool cleanup_processor(byte *arg);
virtual bool collect_item_field_processor(byte * arg) { return 0; }
+ virtual bool change_context_processor(byte *context) { return 0; }
+ virtual bool reset_query_id_processor(byte *query_id) { return 0; }
+
virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual Item *set_no_const_sub(byte *arg) { return this; }
virtual Item *replace_equal_field(byte * arg) { return this; }
@@ -606,7 +715,7 @@ public:
Item **this_item_addr(THD *thd, Item **);
Item *this_const_item() const;
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void cleanup();
inline uint get_offset()
@@ -662,6 +771,7 @@ class Item_num: public Item
{
public:
virtual Item_num *neg()= 0;
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
};
#define NO_CACHED_FIELD_INDEX ((uint)(-1))
@@ -679,7 +789,9 @@ protected:
const char *orig_db_name;
const char *orig_table_name;
const char *orig_field_name;
+
public:
+ Name_resolution_context *context;
const char *db_name;
const char *table_name;
const char *field_name;
@@ -697,17 +809,16 @@ public:
*/
TABLE_LIST *cached_table;
st_select_lex *depended_from;
- Item_ident(const char *db_name_par,const char *table_name_par,
- const char *field_name_par);
+ Item_ident(Name_resolution_context *context_arg,
+ const char *db_name_arg, const char *table_name_arg,
+ const char *field_name_arg);
Item_ident(THD *thd, Item_ident *item);
const char *full_name() const;
void cleanup();
bool remove_dependence_processor(byte * arg);
void print(String *str);
-
- friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
- const char *table_name, List_iterator<Item> *it,
- bool any_privileges, bool allocate_view_names);
+ virtual bool change_context_processor(byte *cntx)
+ { context= (Name_resolution_context *)cntx; return FALSE; }
};
class Item_equal;
@@ -729,12 +840,9 @@ public:
/* field need any privileges (for VIEW creation) */
bool any_privileges;
- Item_field(const char *db_par,const char *table_name_par,
- const char *field_name_par)
- :Item_ident(db_par,table_name_par,field_name_par),
- field(0), result_field(0), item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
- { collation.set(DERIVATION_IMPLICIT); }
+ Item_field(Name_resolution_context *context_arg,
+ const char *db_arg,const char *table_name_arg,
+ const char *field_name_arg);
/*
Constructor needed to process subselect with temporary tables (see Item)
*/
@@ -744,7 +852,7 @@ public:
and database names will live as long as Item_field (this is important
in prepared statements).
*/
- Item_field(THD *thd, Field *field);
+ Item_field(THD *thd, Name_resolution_context *context_arg, Field *field);
/*
If this constructor is used, fix_fields() won't work, because
db_name, table_name and column_name are unknown. It's necessary to call
@@ -764,7 +872,7 @@ public:
bool val_bool_result();
bool send(Protocol *protocol, String *str_arg);
void reset_field(Field *f);
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void make_field(Send_field *tmp_field);
int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
@@ -789,6 +897,13 @@ public:
bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd);
bool collect_item_field_processor(byte * arg);
+ bool reset_query_id_processor(byte *arg)
+ {
+ field->query_id= *((query_id_t *) arg);
+ if (result_field)
+ result_field->query_id= field->query_id;
+ return 0;
+ }
void cleanup();
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg);
@@ -925,7 +1040,6 @@ public:
bool get_time(TIME *tm);
bool get_date(TIME *tm, uint fuzzydate);
int save_in_field(Field *field, bool no_conversions);
- bool fix_fields(THD *, struct st_table_list *, Item **);
void set_null();
void set_int(longlong i, uint32 max_length_arg);
@@ -1018,6 +1132,7 @@ public:
Item_static_int_func(const char *str_arg, longlong i, uint length)
:Item_int(NullS, i, length), func_name(str_arg)
{}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
};
@@ -1128,6 +1243,7 @@ public:
:Item_float(NullS, val_arg, decimal_par, length), func_name(str)
{}
void print(String *str) { str->append(func_name); }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -1158,7 +1274,7 @@ public:
collation.set(cs, dv);
str_value.set_or_copy_aligned(str,length,cs);
max_length= str_value.numchars()*cs->mbmaxlen;
- set_name(name_par,0,cs);
+ set_name(name_par, 0, cs);
decimals=NOT_FIXED_DEC;
// it is constant => can be used without fix_fields (and frequently used)
fixed= 1;
@@ -1200,6 +1316,7 @@ public:
Derivation dv= DERIVATION_COERCIBLE)
:Item_string(NullS, str, length, cs, dv), func_name(name_par)
{}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
};
@@ -1256,6 +1373,7 @@ public:
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
bool eq(const Item *item, bool binary_cmp) const;
+ virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -1296,9 +1414,11 @@ protected:
public:
Field *result_field; /* Save result here */
Item **ref;
- Item_ref(const char *db_par, const char *table_name_par,
- const char *field_name_par)
- :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {}
+ Item_ref(Name_resolution_context *context_arg,
+ const char *db_arg, const char *table_name_arg,
+ const char *field_name_arg)
+ :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg),
+ result_field(0), ref(0) {}
/*
This constructor is used in two scenarios:
A) *item = NULL
@@ -1313,13 +1433,18 @@ public:
TODO we probably fix a superset of problems like in BUG#6658. Check this
with Bar, and if we have a more broader set of problems like this.
*/
- Item_ref(Item **item, const char *table_name_par, const char *field_name_par);
+ Item_ref(Name_resolution_context *context_arg, Item **item,
+ const char *table_name_arg, const char *field_name_arg);
/* Constructor need to process subselect with temporary tables (see Item) */
- Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
+ Item_ref(THD *thd, Item_ref *item)
+ :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
- { return ref && (*ref)->eq(item, binary_cmp); }
+ {
+ Item *it= ((Item *) item)->real_item();
+ return ref && (*ref)->eq(it, binary_cmp);
+ }
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
@@ -1333,10 +1458,9 @@ public:
my_decimal *val_decimal_result(my_decimal *);
bool val_bool_result();
bool send(Protocol *prot, String *tmp);
- void make_field(Send_field *field) { (*ref)->make_field(field); }
- bool fix_fields(THD *, struct st_table_list *, Item **);
- int save_in_field(Field *field, bool no_conversions)
- { return (*ref)->save_in_field(field, no_conversions); }
+ void make_field(Send_field *field);
+ bool fix_fields(THD *, Item **);
+ int save_in_field(Field *field, bool no_conversions);
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
enum_field_types field_type() const { return (*ref)->field_type(); }
@@ -1360,6 +1484,8 @@ public:
{ return (*ref)->walk(processor, arg); }
void print(String *str);
void cleanup();
+ Item_field *filed_for_view_update()
+ { return (*ref)->filed_for_view_update(); }
};
@@ -1370,9 +1496,10 @@ public:
class Item_direct_ref :public Item_ref
{
public:
- Item_direct_ref(Item **item, const char *table_name_par,
- const char *field_name_par)
- :Item_ref(item, table_name_par, field_name_par) {}
+ Item_direct_ref(Name_resolution_context *context_arg, Item **item,
+ const char *table_name_arg,
+ const char *field_name_arg)
+ :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
@@ -1385,6 +1512,25 @@ public:
bool get_date(TIME *ltime,uint fuzzydate);
};
+/*
+ Class for view fields, the same as Item_direct_ref, but call fix_fields
+ of reference if it is not called yet
+*/
+class Item_direct_view_ref :public Item_direct_ref
+{
+public:
+ Item_direct_view_ref(Name_resolution_context *context_arg, Item **item,
+ const char *table_name_arg,
+ const char *field_name_arg)
+ :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ /* Constructor need to process subselect with temporary tables (see Item) */
+ Item_direct_view_ref(THD *thd, Item_direct_ref *item)
+ :Item_direct_ref(thd, item) {}
+
+ bool fix_fields(THD *, Item **);
+ bool eq(const Item *item, bool binary_cmp) const;
+};
+
class Item_in_subselect;
@@ -1393,9 +1539,11 @@ class Item_ref_null_helper: public Item_ref
protected:
Item_in_subselect* owner;
public:
- Item_ref_null_helper(Item_in_subselect* master, Item **item,
- const char *table_name_par, const char *field_name_par):
- Item_ref(item, table_name_par, field_name_par), owner(master) {}
+ Item_ref_null_helper(Name_resolution_context *context_arg,
+ Item_in_subselect* master, Item **item,
+ const char *table_name_arg, const char *field_name_arg)
+ :Item_ref(context_arg, item, table_name_arg, field_name_arg),
+ owner(master) {}
double val_real();
longlong val_int();
String* val_str(String* s);
@@ -1409,10 +1557,11 @@ class Item_null_helper :public Item_ref_null_helper
{
Item *store;
public:
- Item_null_helper(Item_in_subselect* master, Item *item,
- const char *table_name_par, const char *field_name_par)
- :Item_ref_null_helper(master, (store= 0, &store), table_name_par,
- field_name_par),
+ Item_null_helper(Name_resolution_context *context_arg,
+ Item_in_subselect* master, Item *item,
+ const char *table_name_arg, const char *field_name_arg)
+ :Item_ref_null_helper(context_arg, master, (store= 0, &store),
+ table_name_arg, field_name_arg),
store(item)
{ ref= &store; }
void print(String *str);
@@ -1563,13 +1712,17 @@ class Item_default_value : public Item_field
{
public:
Item *arg;
- Item_default_value() :
- Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {}
- Item_default_value(Item *a) :
- Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
+ Item_default_value(Name_resolution_context *context_arg)
+ :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
+ (const char *)NULL),
+ arg(NULL) {}
+ Item_default_value(Name_resolution_context *context_arg, Item *a)
+ :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
+ (const char *)NULL),
+ arg(a) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void print(String *str);
int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
@@ -1598,10 +1751,12 @@ class Item_insert_value : public Item_field
{
public:
Item *arg;
- Item_insert_value(Item *a) :
- Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
+ Item_insert_value(Name_resolution_context *context_arg, Item *a)
+ :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
+ (const char *)NULL),
+ arg(a) {}
bool eq(const Item *item, bool binary_cmp) const;
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void print(String *str);
int save_in_field(Field *field_arg, bool no_conversions)
{
@@ -1663,15 +1818,17 @@ public:
/* Pointer to Table_trigger_list object for table of this trigger */
Table_triggers_list *triggers;
- Item_trigger_field(row_version_type row_ver_par,
- const char *field_name_par):
- Item_field((const char *)NULL, (const char *)NULL, field_name_par),
- row_version(row_ver_par), field_idx((uint)-1)
+ Item_trigger_field(Name_resolution_context *context_arg,
+ row_version_type row_ver_arg,
+ const char *field_name_arg)
+ :Item_field(context_arg,
+ (const char *)NULL, (const char *)NULL, field_name_arg),
+ row_version(row_ver_arg), field_idx((uint)-1)
{}
void setup_field(THD *thd, TABLE *table);
enum Type type() const { return TRIGGER_FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void print(String *str);
table_map used_tables() const { return (table_map)0L; }
void cleanup();
@@ -1860,7 +2017,7 @@ public:
Item_type_holder(THD*, Item*);
Item_result result_type() const;
- virtual enum_field_types field_type() const { return fld_type; };
+ enum_field_types field_type() const { return fld_type; };
enum Type type() const { return TYPE_HOLDER; }
double val_real();
longlong val_int();
@@ -1872,6 +2029,7 @@ public:
static enum_field_types get_real_type(Item *);
};
+
class st_select_lex;
void mark_select_range_as_dependent(THD *thd,
st_select_lex *last_select,
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index a4c42071bb0..a67e420170a 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -60,8 +60,8 @@ bool Cached_item_str::cmp(void)
String *res;
bool tmp;
- res=item->val_str(&tmp_value);
- res->length(min(res->length(), value.alloced_length()));
+ if ((res=item->val_str(&tmp_value)))
+ res->length(min(res->length(), value.alloced_length()));
if (null_value != item->null_value)
{
if ((null_value= item->null_value))
@@ -146,7 +146,7 @@ bool Cached_item_decimal::cmp()
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<Cached_item>;
template class List_iterator<Cached_item>;
#endif
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index eabc89bc429..d7c117db6c0 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -237,30 +237,35 @@ void Item_bool_func2::fix_length_and_dec()
set_cmp_func();
return;
}
-
- if (args[0]->type() == FIELD_ITEM)
+
+ if (!thd->is_context_analysis_only())
{
- Field *field=((Item_field*) args[0])->field;
- if (field->can_be_compared_as_longlong())
+ Item *real_item= args[0]->real_item();
+ if (real_item->type() == FIELD_ITEM)
{
- if (convert_constant_item(thd, field,&args[1]))
+ Field *field=((Item_field*) real_item)->field;
+ if (field->can_be_compared_as_longlong())
{
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- return;
+ if (convert_constant_item(thd, field,&args[1]))
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
+ return;
+ }
}
}
- }
- if (args[1]->type() == FIELD_ITEM /* && !args[1]->const_item() */)
- {
- Field *field=((Item_field*) args[1])->field;
- if (field->can_be_compared_as_longlong())
+ real_item= args[1]->real_item();
+ if (real_item->type() == FIELD_ITEM /* && !real_item->const_item() */)
{
- if (convert_constant_item(thd, field,&args[0]))
+ Field *field=((Item_field*) real_item)->field;
+ if (field->can_be_compared_as_longlong())
{
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- return;
+ if (convert_constant_item(thd, field,&args[0]))
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
+ return;
+ }
}
}
}
@@ -273,7 +278,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
owner= item;
func= comparator_matrix[type]
[test(owner->functype() == Item_func::EQUAL_FUNC)];
- switch(type) {
+ switch (type) {
case ROW_RESULT:
{
uint n= (*a)->cols();
@@ -636,11 +641,9 @@ int Arg_comparator::compare_e_row()
}
-bool Item_in_optimizer::fix_left(THD *thd,
- struct st_table_list *tables,
- Item **ref)
+bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
- if (!args[0]->fixed && args[0]->fix_fields(thd, tables, args) ||
+ if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
return 1;
@@ -649,7 +652,7 @@ bool Item_in_optimizer::fix_left(THD *thd,
If it is preparation PS only then we do not know values of parameters =>
cant't get there values and do not need that values.
*/
- if (!thd->only_prepare())
+ if (!thd->current_arena->is_stmt_prepare())
cache->store(args[0]);
if (cache->cols() == 1)
{
@@ -677,16 +680,15 @@ bool Item_in_optimizer::fix_left(THD *thd,
}
-bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
- Item ** ref)
+bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (fix_left(thd, tables, ref))
+ if (fix_left(thd, ref))
return TRUE;
if (args[0]->maybe_null)
maybe_null=1;
- if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1))
+ if (!args[1]->fixed && args[1]->fix_fields(thd, args+1))
return TRUE;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols())
@@ -991,7 +993,8 @@ void Item_func_between::fix_length_and_dec()
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
- if (field->can_be_compared_as_longlong())
+ if (!thd->is_context_analysis_only() &&
+ field->can_be_compared_as_longlong())
{
/*
The following can't be recoded with || as convert_constant_item
@@ -1420,6 +1423,8 @@ Item *Item_func_case::find_item(String *str)
my_decimal *first_expr_dec, first_expr_dec_val;
longlong first_expr_int;
double first_expr_real;
+ char buff[MAX_FIELD_WIDTH];
+ String buff_str(buff,sizeof(buff),default_charset());
/* These will be initialized later */
LINT_INIT(first_expr_str);
@@ -1433,7 +1438,7 @@ Item *Item_func_case::find_item(String *str)
{
case STRING_RESULT:
// We can't use 'str' here as this may be overwritten
- if (!(first_expr_str= args[first_expr_num]->val_str(&str_value)))
+ if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str)))
return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible
break;
case INT_RESULT:
@@ -1577,6 +1582,25 @@ my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value)
}
+bool Item_func_case::fix_fields(THD *thd, Item **ref)
+{
+ /*
+ buff should match stack usage from
+ Item_func_case::val_int() -> Item_func_case::find_item()
+ */
+ char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
+ bool res= Item_func::fix_fields(thd, ref);
+ /*
+ Call check_stack_overrun after fix_fields to be sure that stack variable
+ is not optimized away
+ */
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
+ return TRUE; // Fatal error flag is set!
+ return res;
+}
+
+
+
void Item_func_case::fix_length_and_dec()
{
Item **agg;
@@ -2308,7 +2332,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
bool
-Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_cond::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
List_iterator<Item> li(list);
@@ -2356,7 +2380,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
// item can be substituted in fix_fields
if ((!item->fixed &&
- item->fix_fields(thd, tables, li.ref())) ||
+ item->fix_fields(thd, li.ref())) ||
(item= *li.ref())->check_cols(1))
return TRUE; /* purecov: inspected */
used_tables_cache|= item->used_tables();
@@ -2743,11 +2767,11 @@ Item_func::optimize_type Item_func_like::select_optimize() const
}
-bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
+bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (Item_bool_func2::fix_fields(thd, tlist, ref) ||
- escape_item->fix_fields(thd, tlist, &escape_item))
+ if (Item_bool_func2::fix_fields(thd, ref) ||
+ escape_item->fix_fields(thd, &escape_item))
return TRUE;
if (!escape_item->const_during_execution())
@@ -2811,13 +2835,13 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
#ifdef USE_REGEX
bool
-Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_func_regex::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if ((!args[0]->fixed &&
- args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) ||
+ args[0]->fix_fields(thd, args)) || args[0]->check_cols(1) ||
(!args[1]->fixed &&
- args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1))
+ args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1))
return TRUE; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
max_length= 1;
@@ -3477,7 +3501,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
} while (swap);
}
-bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+bool Item_equal::fix_fields(THD *thd, Item **ref)
{
List_iterator_fast<Item_field> li(fields);
Item *item;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 7a22e76b217..75c8411b844 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -108,8 +108,8 @@ public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0), save_cache(0)
{}
- bool fix_fields(THD *, struct st_table_list *, Item **);
- bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
+ bool fix_fields(THD *, Item **);
+ bool fix_left(THD *thd, Item **ref);
bool is_null();
/*
Item_in_optimizer item is special boolean function. On value request
@@ -502,11 +502,11 @@ public:
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
- bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
+ bool fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
args[0]->top_level_item();
- return Item_func::fix_fields(thd, tlist, ref);
+ return Item_func::fix_fields(thd, ref);
}
void fix_length_and_dec();
uint decimal_precision() const;
@@ -566,6 +566,7 @@ public:
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
@@ -849,6 +850,12 @@ class Item_func_in :public Item_int_func
bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
+ /*
+ IN() protect from NULL only first argument, if construction like
+ "expression IN ()" will be allowed, we will need to check number of
+ argument here, because "NOT(NULL IN ())" is TRUE.
+ */
+ table_map not_null_tables() const { return args[0]->not_null_tables(); }
};
/* Functions used by where clause */
@@ -961,7 +968,7 @@ public:
optimize_type select_optimize() const;
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "like"; }
- bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
};
#ifdef USE_REGEX
@@ -980,7 +987,7 @@ public:
regex_compiled(0),regex_is_const(0) {}
void cleanup();
longlong val_int();
- bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
const char *func_name() const { return "regexp"; }
void print(String *str) { print_op(str); }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
@@ -1024,7 +1031,7 @@ public:
:Item_bool_func(), list(nlist), abort_on_null(0) {}
bool add(Item *item) { return list.push_back(item); }
void add_at_head(List<Item> *nlist) { list.prepand(nlist); }
- bool fix_fields(THD *, struct st_table_list *, Item **ref);
+ bool fix_fields(THD *, Item **ref);
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
@@ -1033,7 +1040,7 @@ public:
void print(String *str);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
- COND **conds);
+ COND **conds);
void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg);
@@ -1141,7 +1148,7 @@ public:
void sort(Item_field_cmpfunc cmp, void *arg);
friend class Item_equal_iterator;
void fix_length_and_dec();
- bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
void update_used_tables();
bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index b9073a6c0b3..b7d8d50f9b3 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -299,16 +299,8 @@ Item *create_func_pow(Item* a, Item *b)
Item *create_func_current_user()
{
- THD *thd=current_thd;
- char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
- uint length;
-
- thd->lex->safe_to_cache_query= 0;
- length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) -
- buff);
- return new Item_static_string_func("current_user()",
- thd->memdup(buff, length), length,
- system_charset_info);
+ current_thd->lex->safe_to_cache_query= 0;
+ return new Item_func_user(TRUE);
}
Item *create_func_radians(Item *a)
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 71620a68c34..c3bdb11418f 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -193,12 +193,24 @@ bool Item_func::agg_arg_charsets(DTCollation &coll,
if ((*arg)->type() == FIELD_ITEM)
((Item_field *)(*arg))->no_const_subst= 1;
/*
+ If in statement prepare, then we create a converter for two
+ constant items, do it once and then reuse it.
+ If we're in execution of a prepared statement, arena is NULL,
+ and the conv was created in runtime memory. This can be
+ the case only if the argument is a parameter marker ('?'),
+ because for all true constants the charset converter has already
+ been created in prepare. In this case register the change for
+ rollback.
+ */
+ if (arena)
+ *arg= conv;
+ else
+ thd->change_item_tree(arg, conv);
+ /*
We do not check conv->fixed, because Item_func_conv_charset which can
- be return by safe_charset_converter can't be fixed at creation, also
- it do not need tables (second argument) for name resolving
+ be return by safe_charset_converter can't be fixed at creation
*/
- *arg= conv;
- conv->fix_fields(thd, 0, arg);
+ conv->fix_fields(thd, arg);
}
if (arena)
thd->restore_backup_item_arena(arena, &backup);
@@ -261,7 +273,6 @@ Item_func::Item_func(THD *thd, Item_func *item)
SYNOPSIS:
fix_fields()
thd Thread object
- tables List of all open tables involved in the query
ref Pointer to where this object is used. This reference
is used if we want to replace this object with another
one (for example in the summary functions).
@@ -290,7 +301,7 @@ Item_func::Item_func(THD *thd, Item_func *item)
*/
bool
-Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_func::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end;
@@ -312,7 +323,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
We can't yet set item to *arg as fix_fields may change *arg
We shouldn't call fix_fields() twice, so check 'fixed' field first
*/
- if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)))
+ if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg)))
return TRUE; /* purecov: inspected */
item= *arg;
@@ -568,6 +579,17 @@ String *Item_real_func::val_str(String *str)
}
+my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ double nr= val_real();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
+ return decimal_value;
+}
+
+
void Item_func::fix_num_length_and_dec()
{
decimals= 0;
@@ -1061,6 +1083,14 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
}
+void Item_decimal_typecast::print(String *str)
+{
+ str->append("cast(", 5);
+ args[0]->print(str);
+ str->append(" as decimal)", 12);
+}
+
+
double Item_func_plus::real_op()
{
double value= args[0]->val_real() + args[1]->val_real();
@@ -1874,8 +1904,7 @@ void Item_func_round::fix_length_and_dec()
return;
}
- switch (args[0]->result_type())
- {
+ switch (args[0]->result_type()) {
case REAL_RESULT:
case STRING_RESULT:
hybrid_type= REAL_RESULT;
@@ -1883,16 +1912,17 @@ void Item_func_round::fix_length_and_dec()
max_length= float_length(decimals);
break;
case INT_RESULT:
- if ((decimals_to_set==0) &&
+ if (!decimals_to_set &&
(truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)))
{
+ int length_can_increase= test(!truncate && (args[1]->val_int() < 0));
+ max_length= args[0]->max_length + length_can_increase;
/* Here we can keep INT_RESULT */
hybrid_type= INT_RESULT;
- int length_can_increase= !truncate && (args[1]->val_int() < 0);
- max_length= args[0]->max_length + length_can_increase;
decimals= 0;
break;
}
+ /* fall through */
case DECIMAL_RESULT:
{
hybrid_type= DECIMAL_RESULT;
@@ -2002,10 +2032,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
}
-bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables,
- Item **ref)
+bool Item_func_rand::fix_fields(THD *thd,Item **ref)
{
- if (Item_real_func::fix_fields(thd, tables, ref))
+ if (Item_real_func::fix_fields(thd, ref))
return TRUE;
used_tables_cache|= RAND_TABLE_BIT;
if (arg_count)
@@ -2596,7 +2625,7 @@ void udf_handler::cleanup()
bool
-udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
+udf_handler::fix_fields(THD *thd, Item_result_field *func,
uint arg_count, Item **arguments)
{
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
@@ -2638,7 +2667,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg++,i++)
{
if (!(*arg)->fixed &&
- (*arg)->fix_fields(thd, tables, arg))
+ (*arg)->fix_fields(thd, arg))
DBUG_RETURN(1);
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
@@ -3128,7 +3157,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
THD* thd=current_thd;
User_level_lock* ull;
struct timespec abstime;
- int lock_name_len,error=0;
+ int lock_name_len;
lock_name_len=strlen(lock_name);
pthread_mutex_lock(&LOCK_user_locks);
@@ -3162,8 +3191,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
set_timespec(abstime,lock_timeout);
while (!thd->killed &&
- (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
- != ETIME && error != ETIMEDOUT && ull->locked) ;
+ pthread_cond_timedwait(&ull->cond, &LOCK_user_locks,
+ &abstime) != ETIMEDOUT && ull->locked) ;
if (ull->locked)
{
if (!--ull->count)
@@ -3265,14 +3294,14 @@ longlong Item_func_get_lock::val_int()
set_timespec(abstime,timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
- != ETIME && error != ETIMEDOUT && error != EINVAL && ull->locked) ;
+ != ETIMEDOUT && error != EINVAL && ull->locked) ;
if (thd->killed)
error=EINTR; // Return NULL
if (ull->locked)
{
if (!--ull->count)
delete ull; // Should never happen
- if (error != ETIME && error != ETIMEDOUT)
+ if (error != ETIMEDOUT)
{
error=1;
null_value=1; // Return NULL
@@ -3450,12 +3479,11 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
SELECT @a:= ).
*/
-bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
- Item **ref)
+bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
/* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
- if (Item_func::fix_fields(thd, tables, ref) ||
+ if (Item_func::fix_fields(thd, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return TRUE;
/*
@@ -4111,7 +4139,7 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
return 1; // Same item is same.
/* Check if other type is also a get_user_var() object */
if (item->type() != FUNC_ITEM ||
- ((Item_func*) item)->func_name() != func_name())
+ ((Item_func*) item)->functype() != functype())
return 0;
Item_func_get_user_var *other=(Item_func_get_user_var*) item;
return (name.length == other->name.length &&
@@ -4119,11 +4147,10 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
}
-bool Item_user_var_as_out_param::fix_fields(THD *thd, TABLE_LIST *tables,
- Item **ref)
+bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (Item::fix_fields(thd, tables, ref) ||
+ if (Item::fix_fields(thd, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return TRUE;
entry->type= STRING_RESULT;
@@ -4190,6 +4217,36 @@ void Item_user_var_as_out_param::print(String *str)
}
+Item_func_get_system_var::
+Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+ LEX_STRING *component_arg, const char *name_arg,
+ size_t name_len_arg)
+ :var(var_arg), var_type(var_type_arg), component(*component_arg)
+{
+ /* set_name() will allocate the name */
+ set_name(name_arg, name_len_arg, system_charset_info);
+}
+
+
+bool
+Item_func_get_system_var::fix_fields(THD *thd, Item **ref)
+{
+ Item *item= var->item(thd, var_type, &component);
+ DBUG_ENTER("Item_func_get_system_var::fix_fields");
+ /*
+ Evaluate the system variable and substitute the result (a basic constant)
+ instead of this item. If the variable can not be evaluated,
+ the error is reported in sys_var::item().
+ */
+ if (item == 0)
+ DBUG_RETURN(1); // Impossible
+ item->set_name(name, 0, system_charset_info); // don't allocate a new name
+ thd->change_item_tree(ref, item);
+
+ DBUG_RETURN(0);
+}
+
+
longlong Item_func_inet_aton::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -4306,7 +4363,7 @@ void Item_func_match::init_search(bool no_order)
}
-bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
+bool Item_func_match::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
Item *item;
@@ -4321,7 +4378,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
modifications to find_best and auto_close as complement to auto_init code
above.
*/
- if (Item_func::fix_fields(thd, tlist, ref) ||
+ if (Item_func::fix_fields(thd, ref) ||
!args[0]->const_during_execution())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
@@ -4368,6 +4425,9 @@ bool Item_func_match::fix_index()
if (key == NO_SUCH_KEY)
return 0;
+
+ if (!table)
+ goto err;
for (keynr=0 ; keynr < table->s->keys ; keynr++)
{
@@ -4443,7 +4503,8 @@ err:
bool Item_func_match::eq(const Item *item, bool binary_cmp) const
{
- if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC ||
+ if (item->type() != FUNC_ITEM ||
+ ((Item_func*)item)->functype() != FT_FUNC ||
flags != ((Item_func_match*)item)->flags)
return 0;
@@ -4532,22 +4593,21 @@ longlong Item_func_bit_xor::val_int()
0 error
# constant item
*/
-
+
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component)
{
+ sys_var *var;
+ char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
+ LEX_STRING *base_name, *component_name;
+
if (component.str == 0 &&
!my_strcasecmp(system_charset_info, name.str, "VERSION"))
return new Item_string("@@VERSION", server_version,
(uint) strlen(server_version),
system_charset_info, DERIVATION_SYSCONST);
- Item *item;
- sys_var *var;
- char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
- LEX_STRING *base_name, *component_name;
-
if (component.str)
{
base_name= &component;
@@ -4569,9 +4629,8 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
return 0;
}
}
- if (!(item=var->item(thd, var_type, component_name)))
- return 0; // Impossible
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+
buff[0]='@';
buff[1]='@';
pos=buff+2;
@@ -4592,28 +4651,8 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
memcpy(pos, base_name->str, base_name->length);
pos+= base_name->length;
- // set_name() will allocate the name
- item->set_name(buff,(uint) (pos-buff), system_charset_info);
- return item;
-}
-
-
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
- uint length, const char *item_name)
-{
- Item *item;
- sys_var *var;
- LEX_STRING null_lex_string;
-
- null_lex_string.str= 0;
-
- var= find_sys_var(var_name, length);
- DBUG_ASSERT(var != 0);
- if (!(item=var->item(thd, var_type, &null_lex_string)))
- return 0; // Impossible
- thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- item->set_name(item_name, 0, system_charset_info); // Will use original name
- return item;
+ return new Item_func_get_system_var(var, var_type, component_name,
+ buff, pos - buff);
}
@@ -4682,8 +4721,9 @@ longlong Item_func_row_count::val_int()
}
-Item_func_sp::Item_func_sp(sp_name *name)
- :Item_func(), m_name(name), m_sp(NULL), result_field(NULL)
+Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
+ :Item_func(), context(context_arg), m_name(name), m_sp(NULL),
+ result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
@@ -4691,8 +4731,10 @@ Item_func_sp::Item_func_sp(sp_name *name)
}
-Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
- :Item_func(list), m_name(name), m_sp(NULL), result_field(NULL)
+Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
+ sp_name *name, List<Item> &list)
+ :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),
+ result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
@@ -4707,6 +4749,7 @@ Item_func_sp::cleanup()
delete result_field;
result_field= NULL;
}
+ m_sp= NULL;
Item_func::cleanup();
}
@@ -4799,42 +4842,36 @@ Item_func_sp::execute(Item **itp)
DBUG_ENTER("Item_func_sp::execute");
THD *thd= current_thd;
ulong old_client_capabilites;
- int res;
+ int res= -1;
bool save_in_sub_stmt= thd->transaction.in_sub_stmt;
+ my_bool save_no_send_ok;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
st_sp_security_context save_ctx;
#endif
- if (! m_sp)
+ if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE)))
{
- if (!(m_sp= sp_find_function(thd, m_name, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
- DBUG_RETURN(-1);
- }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ goto error;
}
old_client_capabilites= thd->client_capabilities;
thd->client_capabilities &= ~CLIENT_MULTI_RESULTS;
#ifndef EMBEDDED_LIBRARY
- my_bool nsok= thd->net.no_send_ok;
+ 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))
- DBUG_RETURN(-1);
+ goto error_check;
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))
- {
- sp_restore_security_context(thd, m_sp, &save_ctx);
- thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
- DBUG_RETURN(-1);
- }
+ goto error_check_ctx;
#endif
/*
Like for SPs, we don't binlog the substatements. If the statement which
@@ -4842,6 +4879,7 @@ Item_func_sp::execute(Item **itp)
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->transaction.in_sub_stmt= TRUE;
@@ -4857,15 +4895,20 @@ Item_func_sp::execute(Item **itp)
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+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= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
#endif
thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
+error:
DBUG_RETURN(res);
}
@@ -4936,7 +4979,10 @@ Item_func_sp::fix_length_and_dec()
}
if (!(field= sp_result_field()))
+ {
+ context->process_error(current_thd);
DBUG_VOID_RETURN;
+ }
decimals= field->decimals();
max_length= field->field_length;
maybe_null= 1;
diff --git a/sql/item_func.h b/sql/item_func.h
index 1ac1449760f..43a85e6aa0b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -54,7 +54,8 @@ public:
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
NOT_FUNC, NOT_ALL_FUNC,
NOW_FUNC, TRIG_COND_FUNC,
- GUSERVAR_FUNC};
+ GUSERVAR_FUNC, COLLATE_FUNC,
+ EXTRACT_FUNC, CHAR_TYPECAST_FUNC };
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
OPTIMIZE_EQUAL };
enum Type type() const { return FUNC_ITEM; }
@@ -115,7 +116,7 @@ public:
Item_func(List<Item> &list);
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item);
- bool fix_fields(THD *,struct st_table_list *, Item **ref);
+ bool fix_fields(THD *, Item **ref);
table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables();
@@ -123,7 +124,17 @@ public:
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
virtual bool have_rev_func() const { return 0; }
virtual Item *key_item() const { return args[0]; }
- virtual const char *func_name() const { return "?"; }
+ /*
+ This method is used for debug purposes to print the name of an
+ item to the debug log. The second use of this method is as
+ a helper function of print(), where it is applicable.
+ To suit both goals it should return a meaningful,
+ distinguishable and sintactically correct string. This method
+ should not be used for runtime type identification, use enum
+ {Sum}Functype and Item_func::functype()/Item_sum::sum_func()
+ instead.
+ */
+ virtual const char *func_name() const= 0;
virtual bool const_item() const { return const_item_cache; }
inline Item **arguments() const { return args; }
void set_arguments(List<Item> &list);
@@ -176,6 +187,7 @@ public:
Item_real_func(Item *a,Item *b) :Item_func(a,b) {}
Item_real_func(List<Item> &list) :Item_func(list) {}
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
{ DBUG_ASSERT(fixed == 1); return (longlong) val_real(); }
enum Item_result result_type () const { return REAL_RESULT; }
@@ -306,6 +318,8 @@ public:
enum Item_result result_type () const { return DECIMAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
void fix_length_and_dec() {};
+ const char *func_name() const { return "decimal_typecast"; }
+ void print(String *);
};
@@ -506,7 +520,7 @@ public:
class Item_func_acos :public Item_dec_func
{
- public:
+public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "acos"; }
@@ -514,7 +528,7 @@ class Item_func_acos :public Item_dec_func
class Item_func_asin :public Item_dec_func
{
- public:
+public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "asin"; }
@@ -522,7 +536,7 @@ class Item_func_asin :public Item_dec_func
class Item_func_atan :public Item_dec_func
{
- public:
+public:
Item_func_atan(Item *a) :Item_dec_func(a) {}
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
@@ -531,7 +545,7 @@ class Item_func_atan :public Item_dec_func
class Item_func_cos :public Item_dec_func
{
- public:
+public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "cos"; }
@@ -539,7 +553,7 @@ class Item_func_cos :public Item_dec_func
class Item_func_sin :public Item_dec_func
{
- public:
+public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sin"; }
@@ -547,7 +561,7 @@ class Item_func_sin :public Item_dec_func
class Item_func_tan :public Item_dec_func
{
- public:
+public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "tan"; }
@@ -617,7 +631,7 @@ public:
const char *func_name() const { return "rand"; }
bool const_item() const { return 0; }
void update_used_tables();
- bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
};
@@ -634,7 +648,7 @@ class Item_func_units :public Item_real_func
{
char *name;
double mul,add;
- public:
+public:
Item_func_units(char *name_arg,Item *a,double mul_arg,double add_arg)
:Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {}
double val_real();
@@ -853,7 +867,7 @@ public:
class Item_func_benchmark :public Item_int_func
{
ulong loop_count;
- public:
+public:
Item_func_benchmark(ulong loop_count_arg,Item *expr)
:Item_int_func(expr), loop_count(loop_count_arg)
{}
@@ -868,18 +882,19 @@ class Item_func_benchmark :public Item_int_func
class Item_udf_func :public Item_func
{
- protected:
+protected:
udf_handler udf;
public:
- Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {}
+ Item_udf_func(udf_func *udf_arg)
+ :Item_func(), udf(udf_arg) {}
Item_udf_func(udf_func *udf_arg, List<Item> &list)
:Item_func(list), udf(udf_arg) {}
const char *func_name() const { return udf.name(); }
- bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref)
+ bool fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- bool res= udf.fix_fields(thd, tables, this, arg_count, args);
+ bool res= udf.fix_fields(thd, this, arg_count, args);
used_tables_cache= udf.used_tables_cache;
const_item_cache= udf.const_item_cache;
fixed= 1;
@@ -894,9 +909,11 @@ public:
class Item_func_udf_float :public Item_udf_func
{
public:
- Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
- Item_func_udf_float(udf_func *udf_arg, List<Item> &list)
- :Item_udf_func(udf_arg,list) {}
+ Item_func_udf_float(udf_func *udf_arg)
+ :Item_udf_func(udf_arg) {}
+ Item_func_udf_float(udf_func *udf_arg,
+ List<Item> &list)
+ :Item_udf_func(udf_arg, list) {}
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -919,9 +936,11 @@ class Item_func_udf_float :public Item_udf_func
class Item_func_udf_int :public Item_udf_func
{
public:
- Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
- Item_func_udf_int(udf_func *udf_arg, List<Item> &list)
- :Item_udf_func(udf_arg,list) {}
+ Item_func_udf_int(udf_func *udf_arg)
+ :Item_udf_func(udf_arg) {}
+ Item_func_udf_int(udf_func *udf_arg,
+ List<Item> &list)
+ :Item_udf_func(udf_arg, list) {}
longlong val_int();
double val_real() { return (double) Item_func_udf_int::val_int(); }
String *val_str(String *str);
@@ -933,9 +952,10 @@ public:
class Item_func_udf_decimal :public Item_udf_func
{
public:
- Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_decimal(udf_func *udf_arg)
+ :Item_udf_func(udf_arg) {}
Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list)
- :Item_udf_func(udf_arg,list) {}
+ :Item_udf_func(udf_arg, list) {}
longlong val_int();
double val_real();
my_decimal *val_decimal(my_decimal *);
@@ -948,9 +968,10 @@ public:
class Item_func_udf_str :public Item_udf_func
{
public:
- Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_str(udf_func *udf_arg)
+ :Item_udf_func(udf_arg) {}
Item_func_udf_str(udf_func *udf_arg, List<Item> &list)
- :Item_udf_func(udf_arg,list) {}
+ :Item_udf_func(udf_arg, list) {}
String *val_str(String *);
double val_real()
{
@@ -985,8 +1006,10 @@ public:
class Item_func_udf_float :public Item_real_func
{
public:
- Item_func_udf_float(udf_func *udf_arg) :Item_real_func() {}
- Item_func_udf_float(udf_func *udf_arg, List<Item> &list) :Item_real_func(list) {}
+ Item_func_udf_float(udf_func *udf_arg)
+ :Item_real_func() {}
+ Item_func_udf_float(udf_func *udf_arg, List<Item> &list)
+ :Item_real_func(list) {}
double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
};
@@ -994,8 +1017,10 @@ class Item_func_udf_float :public Item_real_func
class Item_func_udf_int :public Item_int_func
{
public:
- Item_func_udf_int(udf_func *udf_arg) :Item_int_func() {}
- Item_func_udf_int(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {}
+ Item_func_udf_int(udf_func *udf_arg)
+ :Item_int_func() {}
+ Item_func_udf_int(udf_func *udf_arg, List<Item> &list)
+ :Item_int_func(list) {}
longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -1003,8 +1028,10 @@ public:
class Item_func_udf_decimal :public Item_int_func
{
public:
- Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {}
- Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {}
+ Item_func_udf_decimal(udf_func *udf_arg)
+ :Item_int_func() {}
+ Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list)
+ :Item_int_func(list) {}
my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -1012,8 +1039,10 @@ public:
class Item_func_udf_str :public Item_func
{
public:
- Item_func_udf_str(udf_func *udf_arg) :Item_func() {}
- Item_func_udf_str(udf_func *udf_arg, List<Item> &list) :Item_func(list) {}
+ Item_func_udf_str(udf_func *udf_arg)
+ :Item_func() {}
+ Item_func_udf_str(udf_func *udf_arg, List<Item> &list)
+ :Item_func(list) {}
String *val_str(String *)
{ DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; }
@@ -1046,7 +1075,7 @@ class Item_func_get_lock :public Item_int_func
class Item_func_release_lock :public Item_int_func
{
String value;
- public:
+public:
Item_func_release_lock(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "release_lock"; }
@@ -1058,7 +1087,7 @@ class Item_func_release_lock :public Item_int_func
class Item_master_pos_wait :public Item_int_func
{
String value;
- public:
+public:
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
Item_master_pos_wait(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
longlong val_int();
@@ -1103,7 +1132,7 @@ public:
bool check();
bool update();
enum Item_result result_type () const { return cached_result_type; }
- bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
void print(String *str);
void print_as_stmt(String *str);
@@ -1163,13 +1192,38 @@ public:
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */
- bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
void print(String *str);
void set_null_value(CHARSET_INFO* cs);
void set_value(const char *str, uint length, CHARSET_INFO* cs);
};
+/* A system variable */
+
+class Item_func_get_system_var :public Item_func
+{
+ sys_var *var;
+ enum_var_type var_type;
+ LEX_STRING component;
+public:
+ Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+ LEX_STRING *component_arg, const char *name_arg,
+ size_t name_len_arg);
+ bool fix_fields(THD *thd, Item **ref);
+ /*
+ Stubs for pure virtual methods. Should never be called: this
+ item is always substituted with a constant in fix_fields().
+ */
+ double val_real() { DBUG_ASSERT(0); return 0.0; }
+ longlong val_int() { DBUG_ASSERT(0); return 0; }
+ String* val_str(String*) { DBUG_ASSERT(0); return 0; }
+ void fix_length_and_dec() { DBUG_ASSERT(0); }
+ /* TODO: fix to support views */
+ const char *func_name() const { return "get_system_var"; }
+};
+
+
class Item_func_inet_aton : public Item_int_func
{
public:
@@ -1217,7 +1271,7 @@ public:
const char *func_name() const { return "match"; }
void update_used_tables() {}
table_map not_null_tables() const { return 0; }
- bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
/* The following should be safe, even if we compare doubles */
longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; }
@@ -1289,6 +1343,7 @@ class sp_name;
class Item_func_sp :public Item_func
{
private:
+ Name_resolution_context *context;
sp_name *m_name;
mutable sp_head *m_sp;
TABLE *dummy_table;
@@ -1301,9 +1356,10 @@ private:
public:
- Item_func_sp(sp_name *name);
+ Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
- Item_func_sp(sp_name *name, List<Item> &list);
+ Item_func_sp(Name_resolution_context *context_arg,
+ sp_name *name, List<Item> &list);
virtual ~Item_func_sp()
{}
@@ -1348,6 +1404,9 @@ public:
return result_field->val_str(str);
}
+ virtual bool change_context_processor(byte *cntx)
+ { context= (Name_resolution_context *)cntx; return FALSE; }
+
void fix_length_and_dec();
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 0c8baa332ca..9362518e6ef 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -53,7 +53,7 @@ void Item_row::illegal_method_call(const char *method)
DBUG_VOID_RETURN;
}
-bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
+bool Item_row::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
null_value= 0;
@@ -61,7 +61,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
Item **arg, **arg_end;
for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
{
- if ((*arg)->fix_fields(thd, tabl, arg))
+ if ((*arg)->fix_fields(thd, arg))
return TRUE;
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
diff --git a/sql/item_row.h b/sql/item_row.h
index e6b23eebb49..6fbe7436b72 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -61,7 +61,7 @@ public:
illegal_method_call((const char*)"val_decimal");
return 0;
};
- bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
bool const_item() const { return const_item_cache; };
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 539bed58e66..ec30dbf8aea 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -363,6 +363,7 @@ String *Item_func_des_encrypt::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
#ifdef HAVE_OPENSSL
+ uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE;
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
@@ -370,13 +371,16 @@ String *Item_func_des_encrypt::val_str(String *str)
uint key_number, res_length, tail;
String *res= args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0;
+ if ((null_value= args[0]->null_value))
+ return 0; // ENCRYPT(NULL) == NULL
if ((res_length=res->length()) == 0)
return &my_empty_string;
if (arg_count == 1)
{
+ /* Make sure LOCK_des_key_file was initialized. */
+ init_des_key_file();
+
/* Protect against someone doing FLUSH DES_KEY_FILE */
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number=des_default_key];
@@ -387,6 +391,10 @@ String *Item_func_des_encrypt::val_str(String *str)
key_number= (uint) args[1]->val_int();
if (key_number > 9)
goto error;
+
+ /* Make sure LOCK_des_key_file was initialized. */
+ init_des_key_file();
+
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number];
VOID(pthread_mutex_unlock(&LOCK_des_key_file));
@@ -419,6 +427,7 @@ String *Item_func_des_encrypt::val_str(String *str)
tail= (8-(res_length) % 8); // 1..8 marking extra length
res_length+=tail;
+ code= ER_OUT_OF_RESOURCES;
if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1))
goto error;
(*res)[res_length-1]=tail; // save extra length
@@ -436,6 +445,13 @@ String *Item_func_des_encrypt::val_str(String *str)
return &tmp_value;
error:
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ code, ER(code),
+ "des_encrypt");
+#else
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED),
+ "des_encrypt","--with-openssl");
#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
@@ -446,12 +462,12 @@ String *Item_func_des_decrypt::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
#ifdef HAVE_OPENSSL
- DES_key_schedule ks1, ks2, ks3;
+ uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE;
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
String *res= args[0]->val_str(str);
- uint length=res->length(),tail;
+ uint length= 0, tail;
if ((null_value=args[0]->null_value))
return 0;
@@ -465,6 +481,10 @@ String *Item_func_des_decrypt::val_str(String *str)
// Check if automatic key and that we have privilege to uncompress using it
if (!(current_thd->master_access & SUPER_ACL) || key_number > 9)
goto error;
+
+ /* Make sure LOCK_des_key_file was initialized. */
+ init_des_key_file();
+
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number];
VOID(pthread_mutex_unlock(&LOCK_des_key_file));
@@ -485,6 +505,7 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2);
DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3);
}
+ code= ER_OUT_OF_RESOURCES;
if (tmp_value.alloc(length-1))
goto error;
@@ -498,11 +519,19 @@ String *Item_func_des_decrypt::val_str(String *str)
&ivec, FALSE);
/* Restore old length of key */
if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
- goto error; // Wrong key
+ goto wrong_key; // Wrong key
tmp_value.length(length-1-tail);
return &tmp_value;
error:
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ code, ER(code),
+ "des_decrypt");
+wrong_key:
+#else
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED),
+ "des_decrypt","--with-openssl");
#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
@@ -1037,7 +1066,8 @@ void Item_func_substr::fix_length_and_dec()
collation.set(args[0]->collation);
if (args[1]->const_item())
{
- int32 start=(int32) args[1]->val_int()-1;
+ int32 start= (int32) args[1]->val_int();
+ start= (int32)((start < 0) ? max_length + start : start - 1);
if (start < 0 || start >= (int32) max_length)
max_length=0; /* purecov: inspected */
else
@@ -1522,9 +1552,11 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
uint conv_errors;
String tmp, cstr, *ostr= val_str(&tmp);
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
+ if (conv_errors ||
+ !(conv= new Item_static_string_func(fully_qualified_func_name(),
+ cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
{
return NULL;
}
@@ -1554,13 +1586,24 @@ String *Item_func_user::val_str(String *str)
DBUG_ASSERT(fixed == 1);
THD *thd=current_thd;
CHARSET_INFO *cs= system_charset_info;
- const char *host= thd->host_or_ip;
+ const char *host, *user;
uint res_length;
+ if (is_current)
+ {
+ user= thd->priv_user;
+ host= thd->priv_host;
+ }
+ else
+ {
+ user= thd->user;
+ host= thd->host_or_ip;
+ }
+
// For system threads (e.g. replication SQL thread) user may be empty
- if (!thd->user)
+ if (!user)
return &my_empty_string;
- res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
+ res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
if (str->alloc(res_length))
{
@@ -1568,12 +1611,13 @@ String *Item_func_user::val_str(String *str)
return 0;
}
res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",
- thd->user, host);
+ user, host);
str->length(res_length);
str->set_charset(cs);
return str;
}
+
void Item_func_soundex::fix_length_and_dec()
{
collation.set(args[0]->collation);
@@ -2297,7 +2341,7 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
return 0;
Item_func *item_func=(Item_func*) item;
if (arg_count != item_func->arg_count ||
- func_name() != item_func->func_name())
+ functype() != item_func->functype())
return 0;
Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item;
if (collation.collation != item_func_sc->collation.collation)
@@ -2350,9 +2394,22 @@ String *Item_func_hex::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (args[0]->result_type() != STRING_RESULT)
{
- /* Return hex of unsigned longlong value */
- longlong dec= args[0]->val_int();
+ ulonglong dec;
char ans[65],*ptr;
+ /* Return hex of unsigned longlong value */
+ if (args[0]->result_type() == REAL_RESULT ||
+ args[0]->result_type() == DECIMAL_RESULT)
+ {
+ double val= args[0]->val_real();
+ if ((val <= (double) LONGLONG_MIN) ||
+ (val >= (double) (ulonglong) ULONGLONG_MAX))
+ dec= ~(longlong) 0;
+ else
+ dec= (ulonglong) (val + (val > 0 ? 0.5 : -0.5));
+ }
+ else
+ dec= (ulonglong) args[0]->val_int();
+
if ((null_value= args[0]->null_value))
return 0;
ptr= longlong2str(dec,ans,16);
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 6df90cebdff..fa098849a43 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -95,6 +95,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "concat_ws"; }
+ table_map not_null_tables() const { return 0; }
};
class Item_func_reverse :public Item_str_func
@@ -322,7 +323,7 @@ public:
Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length = 13; }
- const char *func_name() const { return "ecrypt"; }
+ const char *func_name() const { return "encrypt"; }
};
#include "sql_crypt.h"
@@ -356,8 +357,15 @@ public:
Item_func_sysconst()
{ collation.set(system_charset_info,DERIVATION_SYSCONST); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
+ /*
+ Used to create correct Item name in new converted item in
+ safe_charset_converter, return string representation of this function
+ call
+ */
+ virtual const char *fully_qualified_func_name() const = 0;
};
+
class Item_func_database :public Item_func_sysconst
{
public:
@@ -369,18 +377,27 @@ public:
maybe_null=1;
}
const char *func_name() const { return "database"; }
+ const char *fully_qualified_func_name() const { return "database()"; }
};
+
class Item_func_user :public Item_func_sysconst
{
+ bool is_current;
+
public:
- Item_func_user() :Item_func_sysconst() {}
+ Item_func_user(bool is_current_arg)
+ :Item_func_sysconst(), is_current(is_current_arg) {}
String *val_str(String *);
- void fix_length_and_dec()
- {
- max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen;
+ void fix_length_and_dec()
+ {
+ max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
+ system_charset_info->mbmaxlen);
}
- const char *func_name() const { return "user"; }
+ const char *func_name() const
+ { return is_current ? "current_user" : "user"; }
+ const char *fully_qualified_func_name() const
+ { return is_current ? "current_user()" : "user()"; }
};
@@ -415,12 +432,12 @@ class Item_func_make_set :public Item_str_func
public:
Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {}
String *val_str(String *str);
- bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
+ bool fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- return ((!item->fixed && item->fix_fields(thd, tlist, &item)) ||
+ return ((!item->fixed && item->fix_fields(thd, &item)) ||
item->check_cols(1) ||
- Item_func::fix_fields(thd, tlist, ref));
+ Item_func::fix_fields(thd, ref));
}
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
void fix_length_and_dec();
@@ -573,6 +590,7 @@ public:
max_length=args[0]->max_length;
}
void print(String *str);
+ const char *func_name() const { return "cast_as_binary"; }
};
@@ -648,6 +666,7 @@ public:
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "collate"; }
+ enum Functype func_type() const { return COLLATE_FUNC; }
void print(String *str);
Item_field *filed_for_view_update()
{
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 393cb87c113..ad1c9977e5b 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -130,7 +130,7 @@ Item_subselect::select_transformer(JOIN *join)
}
-bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
+bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
char const *save_where= thd_param->where;
bool res;
@@ -165,7 +165,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
substitution= 0;
thd->where= "checking transformed subquery";
if (!(*ref)->fixed)
- ret= (*ref)->fix_fields(thd, tables, ref);
+ ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where;
return ret;
}
@@ -194,15 +194,8 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
bool Item_subselect::exec()
{
int res;
- MEM_ROOT *old_root= thd->mem_root;
- /*
- As this is execution, all objects should be allocated through the main
- mem root
- */
- thd->mem_root= &thd->main_mem_root;
res= engine->exec();
- thd->mem_root= old_root;
if (engine_changed)
{
@@ -840,7 +833,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
reference, also Item_sum_(max|min) can't be fixed after creation, so
we do not check item->fixed
*/
- if (item->fix_fields(thd, join->tables_list, 0))
+ if (item->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
/* we added aggregate function => we have to change statistic */
count_field_types(&join->tmp_table_param, join->all_fields, 0);
@@ -869,7 +862,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
- if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
+ if (!optimizer || optimizer->fix_left(thd, 0))
{
thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
@@ -880,7 +873,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
As far as Item_ref_in_optimizer do not substitute itself on fix_fields
we can use same item for all selects.
*/
- expr= new Item_direct_ref((Item**)optimizer->get_cache(),
+ expr= new Item_direct_ref(&select_lex->context,
+ (Item**)optimizer->get_cache(),
(char *)"<no matter>",
(char *)in_left_expr_name);
@@ -900,7 +894,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
{
bool tmp;
Item *item= func->create(expr,
- new Item_ref_null_helper(this,
+ new Item_ref_null_helper(&select_lex->context,
+ this,
select_lex->
ref_pointer_array,
(char *)"<ref>",
@@ -920,7 +915,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
we do not check join->having->fixed, because Item_and (from and_items)
or comparison function (from func->create) can't be fixed after creation
*/
- tmp= join->having->fix_fields(thd, join->tables_list, 0);
+ tmp= join->having->fix_fields(thd, 0);
select_lex->having_fix_field= 0;
if (tmp)
DBUG_RETURN(RES_ERROR);
@@ -956,7 +951,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
and_items) or comparison function (from func->create) can't be
fixed after creation
*/
- tmp= join->having->fix_fields(thd, join->tables_list, 0);
+ tmp= join->having->fix_fields(thd, 0);
select_lex->having_fix_field= 0;
if (tmp)
DBUG_RETURN(RES_ERROR);
@@ -978,7 +973,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
we do not check join->conds->fixed, because Item_and can't be fixed
after creation
*/
- if (join->conds->fix_fields(thd, join->tables_list, 0))
+ if (join->conds->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
}
else
@@ -990,22 +985,23 @@ Item_in_subselect::single_value_transformer(JOIN *join,
comparison functions can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
- */
- item= func->create(expr,
- new Item_null_helper(this, item,
- (char *)"<no matter>",
- (char *)"<result>"));
+ */
+ item= func->create(expr,
+ new Item_null_helper(&select_lex->context,
+ this, item,
+ (char *)"<no matter>",
+ (char *)"<result>"));
#ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE
if (!abort_on_null && left_expr->maybe_null)
item= new Item_cond_or(new Item_func_isnull(left_expr), item);
#endif
- select_lex->having= join->having= item;
+ select_lex->having= join->having= item;
select_lex->having_fix_field= 1;
/*
we do not check join->having->fixed, because comparison function
(from func->create) can't be fixed after creation
*/
- tmp= join->having->fix_fields(thd, join->tables_list, 0);
+ tmp= join->having->fix_fields(thd, 0);
select_lex->having_fix_field= 0;
if (tmp)
DBUG_RETURN(RES_ERROR);
@@ -1055,7 +1051,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
- if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
+ if (!optimizer || optimizer->fix_left(thd, 0))
{
thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
@@ -1078,12 +1074,14 @@ Item_in_subselect::row_value_transformer(JOIN *join)
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(this,
+ 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((*optimizer->get_cache())->
+ eq_creator.create(new Item_direct_ref(&select_lex->context,
+ (*optimizer->get_cache())->
addr(i),
(char *)"<no matter>",
(char *)in_left_expr_name),
@@ -1106,7 +1104,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
join->having can't be fixed after creation, so we do not check
join->having->fixed
*/
- if (join->having->fix_fields(thd, join->tables_list, 0))
+ if (join->having->fix_fields(thd, 0))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR);
@@ -1125,7 +1123,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
join->conds can't be fixed after creation, so we do not check
join->conds->fixed
*/
- if (join->conds->fix_fields(thd, join->tables_list, 0))
+ if (join->conds->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
}
@@ -1196,8 +1194,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func)
thd->lex->current_select= up= current->return_after_parsing();
result= (!left_expr->fixed &&
- left_expr->fix_fields(thd, up->get_table_list(),
- optimizer->arguments()));
+ left_expr->fix_fields(thd, optimizer->arguments()));
/* fix_fields can change reference to left_expr, we need reassign it */
left_expr= optimizer->arguments()[0];
@@ -1487,7 +1484,7 @@ int subselect_uniquesubquery_engine::exec()
TABLE *table= tab->table;
for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
- if (tab->ref.key_err= (*copy)->copy())
+ if ((tab->ref.key_err= (*copy)->copy()) & 1)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(1);
@@ -1540,7 +1537,7 @@ int subselect_indexsubquery_engine::exec()
for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
- if (tab->ref.key_err= (*copy)->copy())
+ if ((tab->ref.key_err= (*copy)->copy()) & 1)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(1);
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 84935429353..0b5736169fa 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -92,7 +92,7 @@ public:
val_int();
return null_value;
}
- bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ bool fix_fields(THD *thd, Item **ref);
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
@@ -119,9 +119,8 @@ public:
friend class select_subselect;
friend class Item_in_optimizer;
- friend bool Item_field::fix_fields(THD *, TABLE_LIST *, Item **);
- friend bool Item_ref::fix_fields(THD *, TABLE_LIST *, Item **);
- friend bool Item_param::fix_fields(THD *, TABLE_LIST *, Item **);
+ friend bool Item_field::fix_fields(THD *, Item **);
+ friend bool Item_ref::fix_fields(THD *, Item **);
friend void mark_select_range_as_dependent(THD*,
st_select_lex*, st_select_lex*,
Field*, Item*, Item_ident*);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index f7a158ceb5a..d2f1016891b 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -86,7 +86,6 @@ void Item_sum::make_field(Send_field *tmp_field)
void Item_sum::print(String *str)
{
str->append(func_name());
- str->append('(');
for (uint i=0 ; i < arg_count ; i++)
{
if (i)
@@ -194,7 +193,7 @@ my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value)
bool
-Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_sum_num::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
@@ -209,7 +208,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
maybe_null=0;
for (uint i=0 ; i < arg_count ; i++)
{
- if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
+ if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
return TRUE;
set_if_bigger(decimals, args[i]->decimals);
maybe_null |= args[i]->maybe_null;
@@ -254,7 +253,7 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
}
bool
-Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
@@ -269,7 +268,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
// 'item' can be changed during fix_fields
if (!item->fixed &&
- item->fix_fields(thd, tables, args) ||
+ item->fix_fields(thd, args) ||
(item= args[0])->check_cols(1))
return TRUE;
decimals=item->decimals;
@@ -2425,13 +2424,6 @@ longlong Item_sum_count_distinct::val_int()
}
-void Item_sum_count_distinct::print(String *str)
-{
- str->append("count(distinct ", 15);
- args[0]->print(str);
- str->append(')');
-}
-
/****************************************************************************
** Functions to handle dynamic loadable aggregates
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
@@ -2466,6 +2458,20 @@ void Item_udf_sum::cleanup()
}
+void Item_udf_sum::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (i)
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append(')');
+}
+
+
Item *Item_sum_udf_float::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_udf_float(thd, this);
@@ -2760,11 +2766,12 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
*/
Item_func_group_concat::
-Item_func_group_concat(bool distinct_arg, List<Item> *select_list,
+Item_func_group_concat(Name_resolution_context *context_arg,
+ bool distinct_arg, List<Item> *select_list,
SQL_LIST *order_list, String *separator_arg)
:tmp_table_param(0), warning(0),
separator(separator_arg), tree(0), table(0),
- order(0), tables_list(0),
+ order(0), context(context_arg),
arg_count_order(order_list ? order_list->elements : 0),
arg_count_field(select_list->elements),
count_cut_values(0),
@@ -2820,7 +2827,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
tree(item->tree),
table(item->table),
order(item->order),
- tables_list(item->tables_list),
+ context(item->context),
arg_count_order(item->arg_count_order),
arg_count_field(item->arg_count_field),
count_cut_values(item->count_cut_values),
@@ -2940,7 +2947,7 @@ bool Item_func_group_concat::add()
bool
-Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+Item_func_group_concat::fix_fields(THD *thd, Item **ref)
{
uint i; /* for loop variable */
DBUG_ASSERT(fixed == 0);
@@ -2962,7 +2969,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (i=0 ; i < arg_count ; i++)
{
if ((!args[i]->fixed &&
- args[i]->fix_fields(thd, tables, args + i)) ||
+ args[i]->fix_fields(thd, args + i)) ||
args[i]->check_cols(1))
return TRUE;
if (i < arg_count_field)
@@ -2973,7 +2980,6 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
null_value= 1;
thd->allow_sum_func= 1;
max_length= thd->variables.group_concat_max_len;
- tables_list= tables;
fixed= 1;
return FALSE;
}
@@ -3023,7 +3029,7 @@ bool Item_func_group_concat::setup(THD *thd)
tmp table columns.
*/
if (arg_count_order &&
- setup_order(thd, args, tables_list, list, all_fields, *order))
+ setup_order(thd, args, context->table_list, list, all_fields, *order))
DBUG_RETURN(TRUE);
count_field_types(tmp_table_param,all_fields,0);
diff --git a/sql/item_sum.h b/sql/item_sum.h
index bb5d31b4b4f..32a1d8dd923 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -81,9 +81,24 @@ public:
virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
- virtual const char *func_name() const { return "?"; }
+ /*
+ This method is used for debug purposes to print the name of an
+ item to the debug log. The second use of this method is as
+ a helper function of print(), where it is applicable.
+ To suit both goals it should return a meaningful,
+ distinguishable and sintactically correct string. This method
+ should not be used for runtime type identification, use enum
+ {Sum}Functype and Item_func::functype()/Item_sum::sum_func()
+ instead.
+
+ NOTE: for Items inherited from Item_sum, func_name() return part of
+ function name till first argument (including '(') to make difference in
+ names for functions with 'distinct' clause and without 'distinct' and
+ also to make printing of items inherited from Item_sum uniform.
+ */
+ virtual const char *func_name() const= 0;
virtual Item *result_item(Field *field)
- { return new Item_field(field);}
+ { return new Item_field(field); }
table_map used_tables() const { return ~(table_map) 0; } /* Not used */
bool const_item() const { return 0; }
bool is_null() { return null_value; }
@@ -109,7 +124,7 @@ public:
Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {}
Item_sum_num(List<Item> &list) :Item_sum(list) {}
Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {}
- bool fix_fields(THD *, TABLE_LIST *, Item **);
+ bool fix_fields(THD *, Item **);
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -159,7 +174,7 @@ public:
void reset_field();
void update_field();
void no_rows_in_result() {}
- const char *func_name() const { return "sum"; }
+ const char *func_name() const { return "sum("; }
Item *copy_or_same(THD* thd);
};
@@ -200,7 +215,6 @@ public:
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
void reset_field() {} // not used
void update_field() {} // not used
- const char *func_name() const { return "sum_distinct"; }
virtual void no_rows_in_result() {}
void fix_length_and_dec();
enum Item_result result_type () const { return val.traits->type(); }
@@ -224,7 +238,7 @@ public:
Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
- const char *func_name() const { return "sum_distinct"; }
+ const char *func_name() const { return "sum(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
};
@@ -243,7 +257,7 @@ public:
void fix_length_and_dec();
virtual void calculate_val_and_count();
enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
- const char *func_name() const { return "avg_distinct"; }
+ const char *func_name() const { return "avg(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
};
@@ -272,7 +286,7 @@ class Item_sum_count :public Item_sum_int
void reset_field();
void cleanup();
void update_field();
- const char *func_name() const { return "count"; }
+ const char *func_name() const { return "count("; }
Item *copy_or_same(THD* thd);
};
@@ -326,12 +340,11 @@ public:
longlong val_int();
void reset_field() { return ;} // Never called
void update_field() { return ; } // Never called
- const char *func_name() const { return "count_distinct"; }
+ const char *func_name() const { return "count(distinct "; }
bool setup(THD *thd);
void make_unique();
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
- void print(String *str);
};
@@ -389,7 +402,7 @@ public:
Item *result_item(Field *field)
{ return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
- const char *func_name() const { return "avg"; }
+ const char *func_name() const { return "avg("; }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
};
@@ -466,7 +479,8 @@ public:
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
void no_rows_in_result() {}
- const char *func_name() const { return "variance"; }
+ const char *func_name() const
+ { return sample ? "var_samp(" : "variance("; }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
enum Item_result result_type () const { return hybrid_type; }
@@ -501,7 +515,7 @@ class Item_sum_std :public Item_sum_variance
double val_real();
Item *result_item(Field *field)
{ return new Item_std_field(this); }
- const char *func_name() const { return "std"; }
+ const char *func_name() const { return "std("; }
Item *copy_or_same(THD* thd);
enum Item_result result_type () const { return REAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
@@ -530,7 +544,7 @@ protected:
was_values(TRUE)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
- bool fix_fields(THD *, TABLE_LIST *, Item **);
+ bool fix_fields(THD *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
@@ -565,7 +579,7 @@ public:
enum Sumfunctype sum_func () const {return MIN_FUNC;}
bool add();
- const char *func_name() const { return "min"; }
+ const char *func_name() const { return "min("; }
Item *copy_or_same(THD* thd);
};
@@ -578,7 +592,7 @@ public:
enum Sumfunctype sum_func () const {return MAX_FUNC;}
bool add();
- const char *func_name() const { return "max"; }
+ const char *func_name() const { return "max("; }
Item *copy_or_same(THD* thd);
};
@@ -609,7 +623,7 @@ public:
Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_or"; }
+ const char *func_name() const { return "bit_or("; }
Item *copy_or_same(THD* thd);
};
@@ -620,7 +634,7 @@ class Item_sum_and :public Item_sum_bit
Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {}
Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_and"; }
+ const char *func_name() const { return "bit_and("; }
Item *copy_or_same(THD* thd);
};
@@ -630,7 +644,7 @@ class Item_sum_xor :public Item_sum_bit
Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {}
bool add();
- const char *func_name() const { return "bit_xor"; }
+ const char *func_name() const { return "bit_xor("; }
Item *copy_or_same(THD* thd);
};
@@ -647,18 +661,21 @@ protected:
udf_handler udf;
public:
- Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;}
- Item_udf_sum( udf_func *udf_arg, List<Item> &list )
- :Item_sum( list ), udf(udf_arg)
+ Item_udf_sum(udf_func *udf_arg)
+ :Item_sum(), udf(udf_arg)
+ { quick_group=0; }
+ Item_udf_sum(udf_func *udf_arg, List<Item> &list)
+ :Item_sum(list), udf(udf_arg)
{ quick_group=0;}
Item_udf_sum(THD *thd, Item_udf_sum *item)
- :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; }
+ :Item_sum(thd, item), udf(item->udf)
+ { udf.not_original= TRUE; }
const char *func_name() const { return udf.name(); }
- bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+ bool fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
fixed= 1;
- return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
+ return udf.fix_fields(thd, this, this->arg_count, this->args);
}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
virtual bool have_field_update(void) const { return 0; }
@@ -668,15 +685,17 @@ public:
void reset_field() {};
void update_field() {};
void cleanup();
+ void print(String *str);
};
class Item_sum_udf_float :public Item_udf_sum
{
public:
- Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_float(udf_func *udf_arg)
+ :Item_udf_sum(udf_arg) {}
Item_sum_udf_float(udf_func *udf_arg, List<Item> &list)
- :Item_udf_sum(udf_arg,list) {}
+ :Item_udf_sum(udf_arg, list) {}
Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
:Item_udf_sum(thd, item) {}
longlong val_int()
@@ -695,9 +714,10 @@ class Item_sum_udf_float :public Item_udf_sum
class Item_sum_udf_int :public Item_udf_sum
{
public:
- Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_int(udf_func *udf_arg)
+ :Item_udf_sum(udf_arg) {}
Item_sum_udf_int(udf_func *udf_arg, List<Item> &list)
- :Item_udf_sum(udf_arg,list) {}
+ :Item_udf_sum(udf_arg, list) {}
Item_sum_udf_int(THD *thd, Item_sum_udf_int *item)
:Item_udf_sum(thd, item) {}
longlong val_int();
@@ -714,7 +734,8 @@ public:
class Item_sum_udf_str :public Item_udf_sum
{
public:
- Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_str(udf_func *udf_arg)
+ :Item_udf_sum(udf_arg) {}
Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
:Item_udf_sum(udf_arg,list) {}
Item_sum_udf_str(THD *thd, Item_sum_udf_str *item)
@@ -752,9 +773,10 @@ public:
class Item_sum_udf_decimal :public Item_udf_sum
{
public:
- Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_decimal(udf_func *udf_arg)
+ :Item_udf_sum(udf_arg) {}
Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list)
- :Item_udf_sum(udf_arg,list) {}
+ :Item_udf_sum(udf_arg, list) {}
Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item)
:Item_udf_sum(thd, item) {}
String *val_str(String *);
@@ -771,7 +793,8 @@ public:
class Item_sum_udf_float :public Item_sum_num
{
public:
- Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_float(udf_func *udf_arg)
+ :Item_sum_num() {}
Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
:Item_sum_num(thd, item) {}
@@ -786,7 +809,8 @@ class Item_sum_udf_float :public Item_sum_num
class Item_sum_udf_int :public Item_sum_num
{
public:
- Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_int(udf_func *udf_arg)
+ :Item_sum_num() {}
Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
Item_sum_udf_int(THD *thd, Item_sum_udf_int *item)
:Item_sum_num(thd, item) {}
@@ -802,15 +826,17 @@ public:
class Item_sum_udf_decimal :public Item_sum_num
{
public:
- Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {}
- Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_decimal(udf_func *udf_arg)
+ :Item_sum_num() {}
+ Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list)
+ :Item_sum_num() {}
Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item)
:Item_sum_num(thd, item) {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
void clear() {}
- bool add() { return 0; }
+ bool add() { return 0; }
void update_field() {}
};
@@ -818,8 +844,10 @@ class Item_sum_udf_decimal :public Item_sum_num
class Item_sum_udf_str :public Item_sum_num
{
public:
- Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {}
- Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_str(udf_func *udf_arg)
+ :Item_sum_num() {}
+ Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
+ :Item_sum_num() {}
Item_sum_udf_str(THD *thd, Item_sum_udf_str *item)
:Item_sum_num(thd, item) {}
String *val_str(String *)
@@ -848,7 +876,7 @@ class Item_func_group_concat : public Item_sum
TREE *tree;
TABLE *table;
ORDER **order;
- TABLE_LIST *tables_list;
+ Name_resolution_context *context;
uint arg_count_order; // total count of ORDER BY items
uint arg_count_field; // count of arguments
uint count_cut_values;
@@ -873,8 +901,9 @@ class Item_func_group_concat : public Item_sum
Item_func_group_concat *group_concat_item);
public:
- Item_func_group_concat(bool is_distinct,List<Item> *is_select,
- SQL_LIST *is_order,String *is_separator);
+ Item_func_group_concat(Name_resolution_context *context_arg,
+ bool is_distinct, List<Item> *is_select,
+ SQL_LIST *is_order, String *is_separator);
Item_func_group_concat(THD *thd, Item_func_group_concat *item);
~Item_func_group_concat() {}
@@ -887,7 +916,7 @@ public:
bool add();
void reset_field() {} // not used
void update_field() {} // not used
- bool fix_fields(THD *, TABLE_LIST *, Item **);
+ bool fix_fields(THD *,Item **);
bool setup(THD *thd);
void make_unique();
double val_real()
@@ -913,4 +942,6 @@ public:
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
void print(String *str);
+ virtual bool change_context_processor(byte *cntx)
+ { context= (Name_resolution_context *)cntx; return FALSE; }
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 564c5e4b9cc..cac9613f1ad 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1753,10 +1753,10 @@ void Item_func_convert_tz::fix_length_and_dec()
bool
-Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref)
+Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref)
{
String str;
- if (Item_date_func::fix_fields(thd_arg, tables_arg, ref))
+ if (Item_date_func::fix_fields(thd_arg, ref))
return TRUE;
tz_tables= thd_arg->lex->time_zone_tables_used;
@@ -2158,7 +2158,7 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1;
if (item->type() != FUNC_ITEM ||
- func_name() != ((Item_func*)item)->func_name())
+ functype() != ((Item_func*)item)->functype())
return 0;
Item_extract* ie= (Item_extract*)item;
@@ -2176,7 +2176,7 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1;
if (item->type() != FUNC_ITEM ||
- func_name() != ((Item_func*)item)->func_name())
+ functype() != ((Item_func*)item)->functype())
return 0;
Item_char_typecast *cast= (Item_char_typecast*)item;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index c8fb2b39836..107d12e6da2 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -503,7 +503,8 @@ public:
Item_func_date_format(Item *a,Item *b,bool is_time_format_arg)
:Item_str_func(a,b),is_time_format(is_time_format_arg) {}
String *val_str(String *str);
- const char *func_name() const { return "date_format"; }
+ const char *func_name() const
+ { return is_time_format ? "time_format" : "date_format"; }
void fix_length_and_dec();
uint format_length(const String *format);
};
@@ -560,7 +561,7 @@ class Item_func_convert_tz :public Item_date_func
double val_real() { return (double) val_int(); }
String *val_str(String *str);
const char *func_name() const { return "convert_tz"; }
- bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
bool get_date(TIME *res, uint fuzzy_date);
void cleanup();
@@ -637,6 +638,7 @@ class Item_extract :public Item_int_func
Item_extract(interval_type type_arg, Item *a)
:Item_int_func(a), int_type(type_arg) {}
longlong val_int();
+ enum Functype functype() const { return EXTRACT_FUNC; }
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
@@ -689,6 +691,7 @@ class Item_char_typecast :public Item_typecast
public:
Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg)
:Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {}
+ enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
const char* cast_type() const { return "char"; };
@@ -790,6 +793,7 @@ public:
return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin));
}
void print(String *str);
+ const char *func_name() const { return "add_time"; }
};
class Item_func_timediff :public Item_str_func
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 14b2e8d53bb..c884c454dac 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -30,6 +30,7 @@ public:
double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
void fix_length_and_dec() { decimals=0; max_length=6; }
void print(String *str) { str->append("0.0", 3); }
+ const char *func_name() const { return "unique_users"; }
};
@@ -46,7 +47,7 @@ public:
bool add() { return 0; }
void reset_field() {}
void update_field() {}
- bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
+ bool fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
fixed= 1;
@@ -58,4 +59,5 @@ public:
}
void print(String *str) { str->append("0.0", 3); }
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
+ const char *func_name() const { return "sum_unique_users"; }
};
diff --git a/sql/lex.h b/sql/lex.h
index d0dc287775e..aa10328ced0 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -214,7 +214,9 @@ static SYMBOL symbols[] = {
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
{ "GET_FORMAT", SYM(GET_FORMAT)},
{ "GLOBAL", SYM(GLOBAL_SYM)},
+#ifdef SP_GOTO
{ "GOTO", SYM(GOTO_SYM)},
+#endif
{ "GRANT", SYM(GRANT)},
{ "GRANTS", SYM(GRANTS)},
{ "GROUP", SYM(GROUP)},
@@ -262,7 +264,10 @@ static SYMBOL symbols[] = {
{ "KEY", SYM(KEY_SYM)},
{ "KEYS", SYM(KEYS)},
{ "KILL", SYM(KILL_SYM)},
+#ifdef SP_GOTO
+ /* QQ This will go away when the GOTO label syntax is fixed */
{ "LABEL", SYM(LABEL_SYM)},
+#endif
{ "LANGUAGE", SYM(LANGUAGE_SYM)},
{ "LAST", SYM(LAST_SYM)},
{ "LEADING", SYM(LEADING)},
diff --git a/sql/lock.cc b/sql/lock.cc
index e0a75a42661..7f3fe5ac5da 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -425,6 +425,19 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
tables+=table_ptr[i]->file->lock_count();
lock_count++;
}
+ /*
+ To be able to open and lock for reading system tables like 'mysql.proc',
+ when we already have some tables opened and locked, and avoid deadlocks
+ we have to disallow write-locking of these tables with any other tables.
+ */
+ if (table_ptr[i]->s->system_table &&
+ table_ptr[i]->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
+ count != 1)
+ {
+ my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db,
+ table_ptr[i]->s->table_name);
+ return 0;
+ }
}
if (!(sql_lock= (MYSQL_LOCK*)
diff --git a/sql/log.cc b/sql/log.cc
index e69c0af15bd..44fff28b612 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1154,6 +1154,9 @@ int MYSQL_LOG::purge_logs(const char *to_log,
*/
if (my_stat(log_info.log_file_name,&s,MYF(0)))
file_size= s.st_size;
+ else
+ sql_print_information("Failed to execute my_stat on file '%s'",
+ log_info.log_file_name);
}
/*
It's not fatal if we can't delete a log file ;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8f109f00c5f..0873ee50743 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2618,13 +2618,15 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev
#ifndef MYSQL_CLIENT
void Load_log_event::set_fields(const char* affected_db,
- List<Item> &field_list)
+ List<Item> &field_list,
+ Name_resolution_context *context)
{
uint i;
const char* field = fields;
for (i= 0; i < num_fields; i++)
{
- field_list.push_back(new Item_field(affected_db, table_name, field));
+ field_list.push_back(new Item_field(context,
+ affected_db, table_name, field));
field+= field_lens[i] + 1;
}
}
@@ -2747,7 +2749,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
thd->query= load_data_query;
if (sql_ex.opt_flags & REPLACE_FLAG)
+ {
handle_dup= DUP_REPLACE;
+ }
else if (sql_ex.opt_flags & IGNORE_FLAG)
{
ignore= 1;
@@ -2789,7 +2793,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
ex.skip_lines = skip_lines;
List<Item> field_list;
- set_fields(thd->db,field_list);
+ thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables);
+ set_fields(thd->db, field_list, &thd->main_lex.select_lex.context);
thd->variables.pseudo_thread_id= thread_id;
List<Item> set_fields;
if (net)
@@ -3617,7 +3622,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
*/
- e.fix_fields(thd, 0, 0);
+ e.fix_fields(thd, 0);
/*
A variable can just be considered as a table with
a single record and with a single column. Thus, like
diff --git a/sql/log_event.h b/sql/log_event.h
index b163a37e7cc..9f4681ae2c5 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -877,7 +877,8 @@ public:
const char* table_name_arg,
List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore,
bool using_trans);
- void set_fields(const char* db, List<Item> &fields_arg);
+ void set_fields(const char* db, List<Item> &fields_arg,
+ Name_resolution_context *context);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 336d493d669..49eb50be580 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -325,6 +325,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
+#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
use strictly more than 64 bits by adding one more define above, you should
@@ -474,6 +475,11 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "protocol.h"
#include "sql_udf.h"
class user_var_entry;
+enum enum_var_type
+{
+ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
+};
+class sys_var;
#include "item.h"
extern my_decimal decimal_zero;
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
@@ -559,8 +565,6 @@ struct Query_cache_query_flags
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
#endif /*HAVE_QUERY_CACHE*/
-#define prepare_execute(A) ((A)->command == COM_EXECUTE)
-
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -668,6 +672,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
bool group, bool modify_item,
+ bool table_cant_handle_bit_fields,
uint convert_blob_length);
void sp_prepare_create_field(THD *thd, create_field *sql_field);
int prepare_create_field(create_field *sql_field,
@@ -726,7 +731,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
bool ignore);
-int check_that_all_fields_are_given_values(THD *thd, TABLE *entry);
+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);
@@ -734,7 +740,7 @@ 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);
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
- bool *refresh);
+ bool *refresh, uint flags);
TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table);
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
bool reopen_table(TABLE *table,bool locked);
@@ -757,7 +763,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
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 check_privileges,
+ bool register_tree_change);
Field *
find_field_in_table(THD *thd, TABLE_LIST *table_list,
const char *name, const char *item_name,
@@ -784,6 +791,7 @@ extern char *des_key_file;
extern struct st_des_keyschedule des_keyschedule[10];
extern uint des_default_key;
extern pthread_mutex_t LOCK_des_key_file;
+void init_des_key_file();
bool load_des_key_file(const char *file_name);
void free_des_key_file();
#endif /* HAVE_OPENSSL */
@@ -842,7 +850,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name);
void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
-void mysql_stmt_free(THD *thd, char *packet);
+void mysql_stmt_close(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
void reinit_stmt_before_use(THD *thd, LEX *lex);
@@ -893,17 +901,29 @@ Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
bool *unaliased);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
-bool insert_fields(THD *thd,TABLE_LIST *tables,
+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 allocate_view_names);
-bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
+ 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);
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, TABLE_LIST *tables,
+bool setup_fields(THD *thd, Item** ref_pointer_array,
List<Item> &item, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func);
+inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
+ List<Item> &item, bool set_query_id,
+ List<Item> *sum_func_list,
+ bool allow_sum_func)
+{
+ bool res;
+ thd->lex->select_lex.no_wrap_view_item= TRUE;
+ res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list,
+ allow_sum_func);
+ thd->lex->select_lex.no_wrap_view_item= FALSE;
+ return res;
+}
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
int setup_ftfuncs(SELECT_LEX* select);
@@ -1232,7 +1252,7 @@ int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
int readfrm(const char *name, const void** data, uint* length);
int writefrm(const char* name, const void* data, uint len);
int closefrm(TABLE *table);
-db_type get_table_type(const char *name);
+db_type get_table_type(THD *thd, const char *name);
int read_string(File file, gptr *to, uint length);
void free_blobs(TABLE *table);
int set_zone(int nr,int min_zone,int max_zone);
@@ -1289,7 +1309,7 @@ ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
ulong next_io_size(ulong pos);
void append_unescaped(String *res, const char *pos, uint length);
-int create_frm(char *name,uint reclength,uchar *fileinfo,
+int create_frm(THD *thd, char *name,uint reclength,uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys);
void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
int rename_file_ext(const char * from,const char * to,const char * ext);
@@ -1314,12 +1334,9 @@ extern bool sql_cache_init();
extern void sql_cache_free();
extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
-/* item.cc */
+/* item_func.cc */
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component);
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
- uint length, const char *item_name);
-/* item_func.cc */
int get_var_with_binlog(THD *thd, LEX_STRING &name,
user_var_entry **out_entry);
/* log.cc */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9c5f33f849d..78d9af387da 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -140,6 +140,7 @@ int deny_severity = LOG_WARNING;
#define zVOLSTATE_DEACTIVE 2
#define zVOLSTATE_MAINTENANCE 3
+#include <nks/netware.h>
#include <nks/vm.h>
#include <library.h>
#include <monitor.h>
@@ -229,6 +230,7 @@ static const char *sql_mode_names[] =
"NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", "STRICT_ALL_TABLES",
"NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO",
"TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE",
+ "NO_ENGINE_SUBSTITUTION",
NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
@@ -2990,9 +2992,7 @@ int win_main(int argc, char **argv)
int main(int argc, char **argv)
#endif
{
-
DEBUGGER_OFF;
-
MY_INIT(argv[0]); // init my_sys library & pthreads
#ifdef _CUSTOMSTARTUPCONFIG_
@@ -3004,14 +3004,15 @@ int main(int argc, char **argv)
#endif
#ifdef __WIN__
-/* Before performing any socket operation (like retrieving hostname */
-/* in init_common_variables we have to call WSAStartup */
- if (!opt_disable_networking)
+ /*
+ Before performing any socket operation (like retrieving hostname
+ in init_common_variables we have to call WSAStartup
+ */
{
WSADATA WsaData;
if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
{
- /* errors are not read yet, so we use test here */
+ /* errors are not read yet, so we use english text here */
my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
unireg_abort(1);
}
@@ -4457,7 +4458,7 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &default_collation_name, (gptr*) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"default-storage-engine", OPT_STORAGE_ENGINE,
- "Set the default storage engine (table tyoe) for tables.", 0, 0,
+ "Set the default storage engine (table type) for tables.", 0, 0,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-table-type", OPT_STORAGE_ENGINE,
"(deprecated) Use --default-storage-engine.", 0, 0,
@@ -5237,7 +5238,7 @@ log and this option does nothing anymore.",
{"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
"Helps in performance tuning in heavily concurrent environments.",
(gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0},
+ 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0},
{"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
" disable a sleep",
@@ -5386,7 +5387,7 @@ The minimum value for this variable is 4096.",
"Default pointer size to be used for MyISAM tables.",
(gptr*) &myisam_data_pointer_size,
(gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
- 6, 2, 8, 0, 1, 0},
+ 6, 2, 7, 0, 1, 0},
{"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
"Deprecated option",
(gptr*) &global_system_variables.myisam_max_extra_sort_file_size,
@@ -6358,9 +6359,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_SLOW_QUERY_LOG:
opt_slow_log=1;
break;
- case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS:
- opt_log_slow_admin_statements= 1;
- break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
@@ -7072,7 +7070,7 @@ static void create_pid_file()
Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class I_List<THD>;
template class I_List_iterator<THD>;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 44539ec2d74..9f6295f8a36 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -135,7 +135,7 @@ my_bool my_net_init(NET *net, Vio* vio)
if (vio != 0) /* If real connection */
{
net->fd = vio_fd(vio); /* For perl DBI/DBD */
-#if defined(MYSQL_SERVER) && !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
+#if defined(MYSQL_SERVER) && !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
if (!(test_flags & TEST_BLOCKING))
{
my_bool old_mode;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 5732e156a7c..676f8d8a33d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -325,7 +325,7 @@ typedef struct st_qsel_param {
TABLE *table;
KEY_PART *key_parts,*key_parts_end;
KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */
- MEM_ROOT *mem_root;
+ MEM_ROOT *mem_root, *old_root;
table_map prev_tables,read_tables,current_table;
uint baseflag, max_key_part, range_count;
@@ -1665,7 +1665,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
keys_to_use.intersect(head->keys_in_use_for_query);
if (!keys_to_use.is_clear_all())
{
- MEM_ROOT *old_root,alloc;
+ MEM_ROOT alloc;
SEL_TREE *tree= NULL;
KEY_PART *key_parts;
KEY *key_info;
@@ -1680,6 +1680,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.table=head;
param.keys=0;
param.mem_root= &alloc;
+ param.old_root= thd->mem_root;
param.needed_reg= &needed_reg;
param.imerge_cost_buff_size= 0;
@@ -1695,7 +1696,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_RETURN(0); // Can't use range
}
key_parts= param.key_parts;
- old_root= thd->mem_root;
thd->mem_root= &alloc;
/*
@@ -1845,7 +1845,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
}
}
- thd->mem_root= old_root;
+ thd->mem_root= param.old_root;
/* If we got a read plan, create a quick select from it. */
if (best_trp)
@@ -1860,7 +1860,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
free_mem:
free_root(&alloc,MYF(0)); // Return memory & allocator
- thd->mem_root= old_root;
+ thd->mem_root= param.old_root;
thd->no_errors=0;
}
@@ -2593,12 +2593,12 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
{
tuple_arg= scan->sel_arg;
/* Here we use the length of the first key part */
- tuple_arg->store_min(key_part->length, &key_ptr, 0);
+ tuple_arg->store_min(key_part->store_length, &key_ptr, 0);
}
while (tuple_arg->next_key_part != sel_arg)
{
tuple_arg= tuple_arg->next_key_part;
- tuple_arg->store_min(key_part[tuple_arg->part].length, &key_ptr, 0);
+ tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0);
}
min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
records= (info->param->table->file->
@@ -3528,15 +3528,13 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
/* Optimize NOT BETWEEN and NOT IN */
Item *arg= cond_func->arguments()[0];
- if (arg->type() == Item::FUNC_ITEM)
- {
- cond_func= (Item_func*) arg;
- if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
- DBUG_RETURN(0);
- inv= TRUE;
- }
- else
+ if (arg->type() != Item::FUNC_ITEM)
DBUG_RETURN(0);
+ cond_func= (Item_func*) arg;
+ if (cond_func->functype() != Item_func::BETWEEN &&
+ cond_func->functype() != Item_func::IN_FUNC)
+ DBUG_RETURN(0);
+ inv= TRUE;
}
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0);
@@ -3581,15 +3579,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(ftree);
}
default:
- if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{
- field_item= (Item_field*) (cond_func->arguments()[0]);
+ field_item= (Item_field*) (cond_func->arguments()[0]->real_item());
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0;
}
else if (cond_func->have_rev_func() &&
- cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
+ cond_func->arguments()[1]->real_item()->type() ==
+ Item::FIELD_ITEM)
{
- field_item= (Item_field*) (cond_func->arguments()[1]);
+ field_item= (Item_field*) (cond_func->arguments()[1]->real_item());
value= cond_func->arguments()[0];
}
else
@@ -3610,7 +3609,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
for (uint i= 0; i < cond_func->arg_count; i++)
{
- Item *arg= cond_func->arguments()[i];
+ Item *arg= cond_func->arguments()[i]->real_item();
if (arg != field_item)
ref_tables|= arg->used_tables();
}
@@ -3695,24 +3694,38 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
{
uint maybe_null=(uint) field->real_maybe_null();
bool optimize_range;
- SEL_ARG *tree;
+ SEL_ARG *tree= 0;
+ MEM_ROOT *alloc= param->mem_root;
char *str;
DBUG_ENTER("get_mm_leaf");
+ /*
+ We need to restore the runtime mem_root of the thread in this
+ function because it evaluates the value of its argument, while
+ the argument can be any, e.g. a subselect. The subselect
+ items, in turn, assume that all the memory allocated during
+ the evaluation has the same life span as the item itself.
+ TODO: opt_range.cc should not reset thd->mem_root at all.
+ */
+ param->thd->mem_root= param->old_root;
if (!value) // IS NULL or IS NOT NULL
{
if (field->table->maybe_null) // Can't use a key on this
- DBUG_RETURN(0);
+ goto end;
if (!maybe_null) // Not null field
- DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
- if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
- DBUG_RETURN(0); // out of memory
+ {
+ if (type == Item_func::ISNULL_FUNC)
+ tree= &null_element;
+ goto end;
+ }
+ if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string)))
+ goto end; // out of memory
if (type == Item_func::ISNOTNULL_FUNC)
{
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
tree->max_flag=NO_MAX_RANGE;
}
- DBUG_RETURN(tree);
+ goto end;
}
/*
@@ -3732,7 +3745,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
key_part->image_type == Field::itRAW &&
((Field_str*)field)->charset() != conf_func->compare_collation() &&
!(conf_func->compare_collation()->state & MY_CS_BINSORT))
- DBUG_RETURN(0);
+ goto end;
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
key_part->part);
@@ -3746,9 +3759,12 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
uint field_length= field->pack_length()+maybe_null;
if (!optimize_range)
- DBUG_RETURN(0); // Can't optimize this
+ goto end;
if (!(res= value->val_str(&tmp)))
- DBUG_RETURN(&null_element);
+ {
+ tree= &null_element;
+ goto end;
+ }
/*
TODO:
@@ -3761,7 +3777,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
res= &tmp;
}
if (field->cmp_type() != STRING_RESULT)
- DBUG_RETURN(0); // Can only optimize strings
+ goto end; // Can only optimize strings
offset=maybe_null;
length=key_part->store_length;
@@ -3786,8 +3802,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
field_length= length;
}
length+=offset;
- if (!(min_str= (char*) alloc_root(param->mem_root, length*2)))
- DBUG_RETURN(0);
+ if (!(min_str= (char*) alloc_root(alloc, length*2)))
+ goto end;
max_str=min_str+length;
if (maybe_null)
@@ -3802,20 +3818,21 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
min_str+offset, max_str+offset,
&min_length, &max_length);
if (like_error) // Can't optimize with LIKE
- DBUG_RETURN(0);
+ goto end;
if (offset != maybe_null) // BLOB or VARCHAR
{
int2store(min_str+maybe_null,min_length);
int2store(max_str+maybe_null,max_length);
}
- DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
+ tree= new (alloc) SEL_ARG(field, min_str, max_str);
+ goto end;
}
if (!optimize_range &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
- DBUG_RETURN(0); // Can't optimize this
+ goto end; // Can't optimize this
/*
We can't always use indexes when comparing a string index to a number
@@ -3824,21 +3841,53 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
if (field->result_type() == STRING_RESULT &&
value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type())
- DBUG_RETURN(0);
+ goto end;
if (value->save_in_field_no_warnings(field, 1) < 0)
{
/* This happens when we try to insert a NULL field in a not null column */
- DBUG_RETURN(&null_element); // cmp with NULL is never TRUE
+ tree= &null_element; // cmp with NULL is never TRUE
+ goto end;
}
- str= (char*) alloc_root(param->mem_root, key_part->store_length+1);
+ str= (char*) alloc_root(alloc, key_part->store_length+1);
if (!str)
- DBUG_RETURN(0);
+ goto end;
if (maybe_null)
*str= (char) field->is_real_null(); // Set to 1 if null
field->get_key_image(str+maybe_null, key_part->length, key_part->image_type);
- if (!(tree=new SEL_ARG(field,str,str)))
- DBUG_RETURN(0); // out of memory
+ if (!(tree= new (alloc) SEL_ARG(field, str, str)))
+ goto end; // out of memory
+
+ /*
+ Check if we are comparing an UNSIGNED integer with a negative constant.
+ In this case we know that:
+ (a) (unsigned_int [< | <=] negative_constant) == FALSE
+ (b) (unsigned_int [> | >=] negative_constant) == TRUE
+ In case (a) the condition is false for all values, and in case (b) it
+ is true for all values, so we can avoid unnecessary retrieval and condition
+ testing, and we also get correct comparison of unsinged integers with
+ negative integers (which otherwise fails because at query execution time
+ negative integers are cast to unsigned if compared with unsigned).
+ */
+ if (field->result_type() == INT_RESULT &&
+ value->result_type() == INT_RESULT &&
+ ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag)
+ {
+ longlong item_val= value->val_int();
+ if (item_val < 0)
+ {
+ if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC)
+ {
+ tree->type= SEL_ARG::IMPOSSIBLE;
+ goto end;
+ }
+ if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC)
+ {
+ tree= 0;
+ goto end;
+ }
+ }
+ }
switch (type) {
case Item_func::LT_FUNC:
@@ -3899,6 +3948,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
default:
break;
}
+
+end:
+ param->thd->mem_root= alloc;
DBUG_RETURN(tree);
}
@@ -5992,7 +6044,10 @@ int QUICK_RANGE_SELECT::reset()
next=0;
range= NULL;
cur_range= (QUICK_RANGE**) ranges.buffer;
-
+
+ if (file->inited == handler::NONE && (error= file->ha_index_init(index)))
+ DBUG_RETURN(error);
+
/* Do not allocate the buffers twice. */
if (multi_range_length)
{
@@ -8121,7 +8176,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
(have_max && have_min && (max_res == 0)));
}
/*
- If this is a just a GROUP BY or DISTINCT without MIN or MAX and there
+ If this is just a GROUP BY or DISTINCT without MIN or MAX and there
are equality predicates for the key parts after the group, find the
first sub-group with the extended prefix.
*/
@@ -8524,23 +8579,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
if ((result == HA_ERR_KEY_NOT_FOUND) && (cur_range->flag & EQ_RANGE))
continue; /* Check the next range. */
- else if (result)
+ if (result)
+ {
/*
In no key was found with this upper bound, there certainly are no keys
in the ranges to the left.
*/
return result;
-
+ }
/* A key was found. */
if (cur_range->flag & EQ_RANGE)
- return result; /* No need to perform the checks below for equal keys. */
+ return 0; /* No need to perform the checks below for equal keys. */
/* Check if record belongs to the current group. */
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len))
- {
- result = HA_ERR_KEY_NOT_FOUND;
- continue;
- }
+ continue; // Row not found
/* If there is a lower limit, check if the found key is in the range. */
if ( !(cur_range->flag & NO_MIN_RANGE) )
@@ -8918,7 +8971,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
** Instantiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<QUICK_RANGE>;
template class List_iterator<QUICK_RANGE>;
#endif
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 57922cdc677..ade94a483a8 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -28,6 +28,7 @@
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
+static void write_eof_packet(THD *thd, NET *net);
#ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length)
@@ -294,7 +295,12 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
DBUG_ENTER("send_ok");
if (net->no_send_ok || !net->vio) // hack for re-parsing queries
+ {
+ DBUG_PRINT("info", ("no send ok: %s, vio present: %s",
+ (net->no_send_ok ? "YES" : "NO"),
+ (net->vio ? "YES" : "NO")));
DBUG_VOID_RETURN;
+ }
buff[0]=0; // No fields
pos=net_store_length(buff+1,(ulonglong) affected_rows);
@@ -357,43 +363,52 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
*/
void
-send_eof(THD *thd, bool no_flush)
+send_eof(THD *thd)
{
NET *net= &thd->net;
DBUG_ENTER("send_eof");
if (net->vio != 0 && !net->no_send_eof)
{
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- uchar buff[5];
- /* Don't send warn count during SP execution, as the warn_list
- is cleared between substatements, and mysqltest gets confused */
- uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
- buff[0]=254;
- int2store(buff+1, tmp);
- /*
- The following test should never be true, but it's better to do it
- because if 'is_fatal_error' is set the server is not going to execute
- other queries (see the if test in dispatch_command / COM_QUERY)
- */
- if (thd->is_fatal_error)
- thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
- int2store(buff+3, thd->server_status);
- VOID(my_net_write(net,(char*) buff,5));
- VOID(net_flush(net));
- }
- else
- {
- VOID(my_net_write(net,eof_buff,1));
- if (!no_flush)
- VOID(net_flush(net));
- }
+ write_eof_packet(thd, net);
+ VOID(net_flush(net));
thd->net.no_send_error= 1;
DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
}
DBUG_VOID_RETURN;
}
+
+/*
+ Format EOF packet according to the current protocol and
+ write it to the network output buffer.
+*/
+
+static void write_eof_packet(THD *thd, NET *net)
+{
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ uchar buff[5];
+ /*
+ Don't send warn count during SP execution, as the warn_list
+ is cleared between substatements, and mysqltest gets confused
+ */
+ uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
+ buff[0]= 254;
+ int2store(buff+1, tmp);
+ /*
+ The following test should never be true, but it's better to do it
+ because if 'is_fatal_error' is set the server is not going to execute
+ other queries (see the if test in dispatch_command / COM_QUERY)
+ */
+ if (thd->is_fatal_error)
+ thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+ int2store(buff+3, thd->server_status);
+ VOID(my_net_write(net, (char*) buff, 5));
+ }
+ else
+ VOID(my_net_write(net, eof_buff, 1));
+}
+
/*
Please client to send scrambled_password in old format.
SYNOPSYS
@@ -635,7 +650,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
}
if (flags & SEND_EOF)
- my_net_write(&thd->net, eof_buff, 1);
+ write_eof_packet(thd, &thd->net);
DBUG_RETURN(prepare_for_send(list));
err:
diff --git a/sql/protocol.h b/sql/protocol.h
index 5b402cb2669..2717d2258fa 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -179,7 +179,7 @@ void net_printf_error(THD *thd, uint sql_errno, ...);
void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
-void send_eof(THD *thd, bool no_flush=0);
+void send_eof(THD *thd);
bool send_old_password_request(THD *thd);
char *net_store_length(char *packet,uint length);
char *net_store_data(char *to,const char *from, uint length);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b22c0924de1..2d7c3364e41 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1617,7 +1617,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
{
if (!(res= var->value->val_str(&str)))
{
- strmake(buff, "NULL", 4);
+ strmov(buff, "NULL");
goto err;
}
var->save_result.ulong_value= ((ulong)
@@ -1652,15 +1652,7 @@ err:
/*
Return an Item for a variable. Used with @@[global.]variable_name
-
If type is not given, return local value if exists, else global
-
- We have to use netprintf() instead of my_error() here as this is
- called on the parsing stage.
-
- TODO:
- With prepared statements/stored procedures this has to be fixed
- to create an item that gets the current value at fix_fields() stage.
*/
Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
@@ -2983,7 +2975,7 @@ int set_var::check(THD *thd)
}
if ((!value->fixed &&
- value->fix_fields(thd, 0, &value)) || value->check_cols(1))
+ value->fix_fields(thd, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
{
@@ -3017,7 +3009,7 @@ int set_var::light_check(THD *thd)
if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
return 1;
- if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) ||
+ if (value && ((!value->fixed && value->fix_fields(thd, &value)) ||
value->check_cols(1)))
return -1;
return 0;
@@ -3046,7 +3038,7 @@ int set_var_user::check(THD *thd)
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
*/
- return (user_var_item->fix_fields(thd, 0, (Item**) 0) ||
+ return (user_var_item->fix_fields(thd, (Item**) 0) ||
user_var_item->check()) ? -1 : 0;
}
@@ -3069,7 +3061,7 @@ int set_var_user::light_check(THD *thd)
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
*/
- return (user_var_item->fix_fields(thd, 0, (Item**) 0));
+ return (user_var_item->fix_fields(thd, (Item**) 0));
}
@@ -3131,7 +3123,7 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
if (!(res=var->value->val_str(&str)) ||
!(var->save_result.ulong_value=
(ulong) (db_type= ha_resolve_by_name(res->ptr(), res->length()))) ||
- ha_checktype(db_type) != db_type)
+ ha_checktype(thd, db_type, 1, 0) != db_type)
{
value= res ? res->c_ptr() : "NULL";
goto err;
@@ -3238,7 +3230,16 @@ void fix_sql_mode_var(THD *thd, enum_var_type type)
global_system_variables.sql_mode=
fix_sql_mode(global_system_variables.sql_mode);
else
+ {
thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode);
+ /*
+ Update thd->server_status
+ */
+ if (thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
+ thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ else
+ thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ }
}
/* Map database specific bits to function bits */
@@ -3406,7 +3407,7 @@ bool process_key_caches(int (* func) (const char *name, KEY_CACHE *))
Used templates
****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<set_var_base>;
template class List_iterator_fast<set_var_base>;
template class I_List_iterator<NAMED_LIST>;
diff --git a/sql/set_var.h b/sql/set_var.h
index a6532323b34..a7e680cc7fa 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -30,11 +30,6 @@ class set_var;
typedef struct system_variables SV;
extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
-enum enum_var_type
-{
- OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
-};
-
typedef int (*sys_check_func)(THD *, set_var *);
typedef bool (*sys_update_func)(THD *, set_var *);
typedef void (*sys_after_update_func)(THD *,enum_var_type);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index a020cadc084..f999f17aedf 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5021,7 +5021,7 @@ ER_NON_UPDATABLE_TABLE
por "A tabela destino %-.100s do %s não é atualizável"
rus "ôÁÂÌÉÃÁ %-.100s × %s ÎÅ ÍÏÖÅÔ ÉÚÍÅÎÑÔÓÑ"
spa "La tabla destino %-.100s del %s no es actualizable"
- swe "Tabel %-.100s använd med '%s' är inte uppdateringsbar"
+ swe "Tabell %-.100s använd med '%s' är inte uppdateringsbar"
ukr "ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ"
ER_FEATURE_DISABLED
eng "The '%s' feature is disabled; you need MySQL built with '%s' to have it working"
@@ -5347,14 +5347,26 @@ ER_SP_NO_RETSET_IN_FUNC 0A000
ER_CANT_CREATE_GEOMETRY_OBJECT 22003
eng "Cannot get geometry object from data you send to the GEOMETRY field"
ER_FAILED_ROUTINE_BREAK_BINLOG
- eng "A routine failed and is declared to modify data and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
+ eng "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"
ER_BINLOG_UNSAFE_ROUTINE
- eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
+ eng "This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
- eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
+ eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)"
ER_EXEC_STMT_WITH_OPEN_CURSOR
eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it."
ER_STMT_HAS_NO_OPEN_CURSOR
- eng "The statement (%d) has no open cursor."
+ eng "The statement (%lu) has no open cursor."
ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
eng "Explicit or implicit commit is not allowed in stored function or trigger."
+ER_NO_DEFAULT_FOR_VIEW_FIELD
+ eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value"
+ER_SP_NO_RECURSION
+ eng "Recursive stored routines are not allowed."
+ER_TOO_BIG_SCALE 42000 S1009
+ eng "Too big scale %d specified for column '%-.64s'. Maximum is %d."
+ER_TOO_BIG_PRECISION 42000 S1009
+ eng "Too big precision %d specified for column '%-.64s'. Maximum is %d."
+ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009
+ eng "Scale may not be larger than the precision (column '%-.64s')."
+ER_WRONG_LOCK_OF_SYSTEM_TABLE
+ eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
diff --git a/sql/slave.cc b/sql/slave.cc
index 60812469671..a587ac5a118 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2753,7 +2753,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
else
pthread_cond_wait(&data_cond, &data_lock);
DBUG_PRINT("info",("Got signal of master update or timed out"));
- if (error == ETIMEDOUT || error == ETIME)
+ if (error == ETIMEDOUT)
{
error= -1;
break;
@@ -5002,7 +5002,7 @@ end:
}
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
#endif
diff --git a/sql/sp.cc b/sql/sp.cc
index 4f89d6ba6da..55087f47f5e 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -19,6 +19,7 @@
#include "sp.h"
#include "sp_head.h"
#include "sp_cache.h"
+#include "sql_trigger.h"
static bool
create_string(THD *thd, String *buf,
@@ -61,57 +62,152 @@ bool mysql_proc_table_exists= 1;
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
-/* *opened=true means we opened ourselves */
-static int
-db_find_routine_aux(THD *thd, int type, sp_name *name,
- enum thr_lock_type ltype, TABLE **tablep, bool *opened)
+
+/*
+ Close mysql.proc, opened with open_proc_table_for_read().
+
+ SYNOPSIS
+ close_proc_table()
+ thd Thread context
+*/
+
+static void close_proc_table(THD *thd)
{
- TABLE *table;
- byte key[NAME_LEN*2+4+1]; // db, name, optional key length type
- DBUG_ENTER("db_find_routine_aux");
- DBUG_PRINT("enter", ("type: %d name: %*s",
- type, name->m_name.length, name->m_name.str));
+ close_thread_tables(thd);
+ thd->pop_open_tables_state();
+}
- *opened= FALSE;
- *tablep= 0;
+
+/*
+ Open the mysql.proc table for read.
+
+ SYNOPSIS
+ open_proc_table_for_read()
+ thd Thread context
+
+ NOTES
+ Thanks to restrictions which we put on opening and locking of
+ this table for writing, we can open and lock it for reading
+ even when we already have some other tables open and locked.
+ One must call close_proc_table() to close table opened with
+ this call.
+
+ RETURN
+ 0 Error
+ # Pointer to TABLE object of mysql.proc
+*/
+
+static TABLE *open_proc_table_for_read(THD *thd)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ bool old_open_tables= thd->open_tables != 0;
+ bool refresh;
+ DBUG_ENTER("open_proc_table");
/*
Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
is set when we create or read stored procedure or on flush privileges.
*/
- if (!mysql_proc_table_exists && ltype == TL_READ)
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+ if (!mysql_proc_table_exists)
+ DBUG_RETURN(0);
- if (thd->lex->proc_table)
- table= thd->lex->proc_table->table;
- else
+ if (thd->push_open_tables_state())
+ DBUG_RETURN(0);
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*)"proc";
+ if (!(table= open_table(thd, &tables, thd->mem_root, &refresh,
+ MYSQL_LOCK_IGNORE_FLUSH)))
{
- for (table= thd->open_tables ; table ; table= table->next)
- if (strcmp(table->s->db, "mysql") == 0 &&
- strcmp(table->s->table_name, "proc") == 0)
- break;
+ thd->pop_open_tables_state();
+ mysql_proc_table_exists= 0;
+ DBUG_RETURN(0);
}
- if (!table)
- {
- TABLE_LIST tables;
- memset(&tables, 0, sizeof(tables));
- tables.db= (char*)"mysql";
- tables.table_name= tables.alias= (char*)"proc";
- if (! (table= open_ltable(thd, &tables, ltype)))
- {
- /*
- Under explicit LOCK TABLES or in prelocked mode we should not
- say that mysql.proc table does not exist if we are unable to
- open it since this condition may be transient.
- */
- if (!(thd->locked_tables || thd->prelocked_mode))
- mysql_proc_table_exists= 0;
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
- *opened= TRUE;
+ DBUG_ASSERT(table->s->system_table);
+
+ 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
+ */
+ if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
+ old_open_tables ?
+ (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
+ MYSQL_LOCK_IGNORE_FLUSH) : 0)))
+ {
+ close_proc_table(thd);
+ DBUG_RETURN(0);
}
- mysql_proc_table_exists= 1;
+ DBUG_RETURN(table);
+}
+
+
+/*
+ Open the mysql.proc table for update.
+
+ SYNOPSIS
+ open_proc_table_for_update()
+ thd Thread context
+
+ NOTES
+ Table opened with this call should closed using close_thread_tables().
+
+ RETURN
+ 0 Error
+ # Pointer to TABLE object of mysql.proc
+*/
+
+static TABLE *open_proc_table_for_update(THD *thd)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ DBUG_ENTER("open_proc_table");
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*)"proc";
+ tables.lock_type= TL_WRITE;
+
+ table= open_ltable(thd, &tables, TL_WRITE);
+
+ /*
+ Under explicit LOCK TABLES or in prelocked mode we should not
+ say that mysql.proc table does not exist if we are unable to
+ open and lock it for writing since this condition may be
+ transient.
+ */
+ if (!(thd->locked_tables || thd->prelocked_mode) || table)
+ mysql_proc_table_exists= test(table);
+
+ DBUG_RETURN(table);
+}
+
+
+/*
+ Find row in open mysql.proc table representing stored routine.
+
+ SYNOPSIS
+ db_find_routine_aux()
+ thd Thread context
+ type Type of routine to find (function or procedure)
+ name Name of routine
+ table TABLE object for open mysql.proc table.
+
+ RETURN VALUE
+ SP_OK - Routine found
+ SP_KEY_NOT_FOUND- No routine with given name
+*/
+
+static int
+db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
+{
+ byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
+ DBUG_ENTER("db_find_routine_aux");
+ DBUG_PRINT("enter", ("type: %d name: %*s",
+ type, name->m_name.length, name->m_name.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -121,9 +217,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
same fields.
*/
if (name->m_name.length > table->field[1]->field_length)
- {
DBUG_RETURN(SP_KEY_NOT_FOUND);
- }
table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
table->field[1]->store(name->m_name.str, name->m_name.length,
&my_charset_bin);
@@ -134,15 +228,33 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
if (table->file->index_read_idx(table->record[0], 0,
key, table->key_info->key_length,
HA_READ_KEY_EXACT))
- {
DBUG_RETURN(SP_KEY_NOT_FOUND);
- }
- *tablep= table;
DBUG_RETURN(SP_OK);
}
+/*
+ Find routine definition in mysql.proc table and create corresponding
+ sp_head object for it.
+
+ SYNOPSIS
+ db_find_routine()
+ thd Thread context
+ type Type of routine (TYPE_ENUM_PROCEDURE/...)
+ name Name of routine
+ sphp Out parameter in which pointer to created sp_head
+ object is returned (0 in case of error).
+
+ NOTE
+ This function may damage current LEX during execution, so it is good
+ idea to create temporary LEX and make it active before calling it.
+
+ RETURN VALUE
+ 0 - Success
+ non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND)
+*/
+
static int
db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
{
@@ -150,7 +262,6 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
TABLE *table;
const char *params, *returns, *body;
int ret;
- bool opened;
const char *definer;
longlong created;
longlong modified;
@@ -164,8 +275,11 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
DBUG_PRINT("enter", ("type: %d name: %*s",
type, name->m_name.length, name->m_name.str));
- ret= db_find_routine_aux(thd, type, name, TL_READ, &table, &opened);
- if (ret != SP_OK)
+ *sphp= 0; // In case of errors
+ if (!(table= open_proc_table_for_read(thd)))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+
+ if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
goto done;
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
@@ -257,11 +371,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
chistics.comment.str= ptr;
chistics.comment.length= length;
- if (opened)
- {
- opened= FALSE;
- close_thread_tables(thd, 0, 1);
- }
+ close_proc_table(thd);
+ table= 0;
{
String defstr;
@@ -337,9 +448,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
}
done:
-
- if (opened)
- close_thread_tables(thd);
+ if (table)
+ close_proc_table(thd);
DBUG_RETURN(ret);
}
@@ -362,7 +472,6 @@ db_create_routine(THD *thd, int type, sp_head *sp)
{
int ret;
TABLE *table;
- TABLE_LIST tables;
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
char olddb[128];
bool dbchanged;
@@ -377,11 +486,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
goto done;
}
- memset(&tables, 0, sizeof(tables));
- tables.db= (char*)"mysql";
- tables.table_name= tables.alias= (char*)"proc";
-
- if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+ if (!(table= open_proc_table_for_update(thd)))
ret= SP_OPEN_TABLE_FAILED;
else
{
@@ -491,20 +596,18 @@ db_drop_routine(THD *thd, int type, sp_name *name)
{
TABLE *table;
int ret;
- bool opened;
DBUG_ENTER("db_drop_routine");
DBUG_PRINT("enter", ("type: %d name: %*s",
type, name->m_name.length, name->m_name.str));
- ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
- if (ret == SP_OK)
+ if (!(table= open_proc_table_for_update(thd)))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+ if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
{
if (table->file->delete_row(table->record[0]))
ret= SP_DELETE_ROW_FAILED;
}
-
- if (opened)
- close_thread_tables(thd);
+ close_thread_tables(thd);
DBUG_RETURN(ret);
}
@@ -519,8 +622,9 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
DBUG_PRINT("enter", ("type: %d name: %*s",
type, name->m_name.length, name->m_name.str));
- ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
- if (ret == SP_OK)
+ if (!(table= open_proc_table_for_update(thd)))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+ if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
{
store_record(table,record[1]);
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@@ -538,8 +642,7 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
if ((table->file->update_row(table->record[1],table->record[0])))
ret= SP_WRITE_ROW_FAILED;
}
- if (opened)
- close_thread_tables(thd);
+ close_thread_tables(thd);
DBUG_RETURN(ret);
}
@@ -676,15 +779,20 @@ db_show_routine_status(THD *thd, int type, const char *wild)
tables is not VIEW for sure => we can pass 0 as condition
*/
- setup_tables(thd, &tables, 0, &leaves, FALSE);
+ thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
+ setup_tables(thd, &thd->lex->select_lex.context,
+ &tables, 0, &leaves, FALSE);
for (used_field= &used_fields[0];
used_field->field_name;
used_field++)
{
- Item_field *field= new Item_field("mysql", "proc",
+ Item_field *field= new Item_field(&thd->lex->select_lex.context,
+ "mysql", "proc",
used_field->field_name);
- if (!(used_field->field= find_field_in_tables(thd, field, &tables,
- 0, REPORT_ALL_ERRORS, 1)))
+ if (!field ||
+ !(used_field->field= find_field_in_tables(thd, field, &tables,
+ 0, REPORT_ALL_ERRORS, 1,
+ TRUE)))
{
res= SP_INTERNAL_ERROR;
goto err_case1;
@@ -736,20 +844,9 @@ sp_drop_db_routines(THD *thd, char *db)
memset(key+keylen, (int)' ', 64-keylen); // Pad with space
keylen= sizeof(key);
- for (table= thd->open_tables ; table ; table= table->next)
- if (strcmp(table->s->db, "mysql") == 0 &&
- strcmp(table->s->table_name, "proc") == 0)
- break;
- if (! table)
- {
- TABLE_LIST tables;
-
- memset(&tables, 0, sizeof(tables));
- tables.db= (char*)"mysql";
- tables.table_name= tables.alias= (char*)"proc";
- if (! (table= open_ltable(thd, &tables, TL_WRITE)))
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
+ ret= SP_OPEN_TABLE_FAILED;
+ if (!(table= open_proc_table_for_update(thd)))
+ goto err;
ret= SP_OK;
table->file->ha_index_init(0);
@@ -759,7 +856,8 @@ sp_drop_db_routines(THD *thd, char *db)
int nxtres;
bool deleted= FALSE;
- do {
+ do
+ {
if (! table->file->delete_row(table->record[0]))
deleted= TRUE; /* We deleted something */
else
@@ -779,6 +877,7 @@ sp_drop_db_routines(THD *thd, char *db)
close_thread_tables(thd);
+err:
DBUG_RETURN(ret);
}
@@ -972,9 +1071,7 @@ sp_find_function(THD *thd, sp_name *name, bool cache_only)
if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
!cache_only)
{
- if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK)
- sp= NULL;
- else
+ if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK)
sp_cache_insert(&thd->sp_func_cache, sp);
}
DBUG_RETURN(sp);
@@ -1052,165 +1149,315 @@ sp_show_status_function(THD *thd, const char *wild)
}
-bool
-sp_function_exists(THD *thd, sp_name *name)
+/*
+ Structure that represents element in the set of stored routines
+ used by statement or routine.
+*/
+struct Sroutine_hash_entry;
+
+struct Sroutine_hash_entry
{
- TABLE *table;
- bool ret= FALSE;
- bool opened= FALSE;
- DBUG_ENTER("sp_function_exists");
-
- if (sp_cache_lookup(&thd->sp_func_cache, name) ||
- db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
- name, TL_READ,
- &table, &opened) == SP_OK)
- ret= TRUE;
- if (opened)
- close_thread_tables(thd, 0, 1);
- thd->clear_error();
- DBUG_RETURN(ret);
-}
+ /* Set key consisting of one-byte routine type and quoted routine name. */
+ LEX_STRING key;
+ /*
+ Next element in list linking all routines in set. See also comments
+ for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
+ */
+ Sroutine_hash_entry *next;
+};
-byte *
-sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first)
+extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first)
{
- LEX_STRING *lsp= (LEX_STRING *)ptr;
- *plen= lsp->length;
- return (byte *)lsp->str;
+ Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr;
+ *plen= rn->key.length;
+ return (byte *)rn->key.str;
}
-void
-sp_add_to_hash(HASH *h, sp_name *fun)
+/*
+ Auxilary function that adds new element to the set of stored routines
+ used by statement.
+
+ SYNOPSIS
+ add_used_routine()
+ lex - LEX representing statement
+ arena - arena in which memory for new element will be allocated
+ key - key for the hash representing set
+
+ NOTES
+ Will also add element to end of 'LEX::sroutines_list' list.
+
+ In case when statement uses stored routines but does not need
+ prelocking (i.e. it does not use any tables) we will access the
+ elements of LEX::sroutines set on prepared statement re-execution.
+ Because of this we have to allocate memory for both hash element
+ and copy of its key in persistent arena.
+
+ TODO
+ When we will got rid of these accesses on re-executions we will be
+ able to allocate memory for hash elements in non-persitent arena
+ and directly use key values from sp_head::m_sroutines sets instead
+ of making their copies.
+
+ RETURN VALUE
+ TRUE - new element was added.
+ FALSE - element was not added (because it is already present in the set).
+*/
+
+static bool add_used_routine(LEX *lex, Query_arena *arena,
+ const LEX_STRING *key)
{
- if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.length))
+ if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
{
- LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
- ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length);
- ls->length= fun->m_qname.length;
-
- my_hash_insert(h, (byte *)ls);
+ Sroutine_hash_entry *rn=
+ (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
+ key->length);
+ if (!rn) // OOM. Error will be reported using fatal_error().
+ return FALSE;
+ rn->key.length= key->length;
+ rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
+ memcpy(rn->key.str, key->str, key->length);
+ my_hash_insert(&lex->sroutines, (byte *)rn);
+ lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
+ return TRUE;
}
+ return FALSE;
+}
+
+
+/*
+ Add routine to the set of stored routines used by statement.
+
+ SYNOPSIS
+ sp_add_used_routine()
+ lex - LEX representing statement
+ arena - arena in which memory for new element of the set
+ will be allocated
+ rt - routine name
+ rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...)
+
+ NOTES
+ Will also add element to end of 'LEX::sroutines_list' list.
+
+ To be friendly towards prepared statements one should pass
+ persistent arena as second argument.
+*/
+
+void sp_add_used_routine(LEX *lex, Query_arena *arena,
+ sp_name *rt, char rt_type)
+{
+ rt->set_routine_type(rt_type);
+ (void)add_used_routine(lex, arena, &rt->m_sroutines_key);
}
/*
- Merge contents of two hashes containing LEX_STRING's
+ Merge contents of two hashes representing sets of routines used
+ by statements or by other routines.
SYNOPSIS
- sp_merge_hash()
+ sp_update_sp_used_routines()
dst - hash to which elements should be added
src - hash from which elements merged
- RETURN VALUE
- TRUE - if we have added some new elements to destination hash.
- FALSE - there were no new elements in src.
+ NOTE
+ This procedure won't create new Sroutine_hash_entry objects,
+ instead it will simply add elements from source to destination
+ hash. Thus time of life of elements in destination hash becomes
+ dependant on time of life of elements from source hash. It also
+ won't touch lists linking elements in source and destination
+ hashes.
*/
-bool
-sp_merge_hash(HASH *dst, HASH *src)
+void sp_update_sp_used_routines(HASH *dst, HASH *src)
{
- bool res= FALSE;
for (uint i=0 ; i < src->records ; i++)
{
- LEX_STRING *ls= (LEX_STRING *)hash_element(src, i);
-
- if (! hash_search(dst, (byte *)ls->str, ls->length))
- {
- my_hash_insert(dst, (byte *)ls);
- res= TRUE;
- }
+ Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
+ if (!hash_search(dst, (byte *)rt->key.str, rt->key.length))
+ my_hash_insert(dst, (byte *)rt);
}
- return res;
}
/*
- Cache all routines implicitly or explicitly used by query
- (or whatever object is represented by LEX).
+ Add contents of hash representing set of routines to the set of
+ routines used by statement.
SYNOPSIS
- sp_cache_routines()
+ sp_update_stmt_used_routines()
thd - thread context
- lex - LEX representing query
+ lex - LEX representing statement
+ src - hash representing set from which routines will be added
+
+ NOTE
+ It will also add elements to end of 'LEX::sroutines_list' list.
+*/
+
+static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
+{
+ for (uint i=0 ; i < src->records ; i++)
+ {
+ Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
+ (void)add_used_routine(lex, thd->current_arena, &rt->key);
+ }
+}
+
+
+/*
+ Cache sub-set of routines used by statement, add tables used by these
+ routines to statement table list. Do the same for all routines used
+ by these routines.
+
+ SYNOPSIS
+ sp_cache_routines_and_add_tables_aux()
+ thd - thread context
+ lex - LEX representing statement
+ start - first routine from the list of routines to be cached
+ (this list defines mentioned sub-set).
NOTE
If some function is missing this won't be reported here.
Instead this fact will be discovered during query execution.
- TODO
- Currently if after passing through routine hashes we discover
- that we have added something to them, we do one more pass to
- process all routines which were missed on previous pass because
- of these additions. We can avoid this if along with hashes
- we use lists holding routine names and iterate other these
- lists instead of hashes (since addition to the end of list
- does not reorder elements in it).
+ RETURN VALUE
+ TRUE - some tables were added
+ FALSE - no tables were added.
*/
-void
-sp_cache_routines(THD *thd, LEX *lex)
+static bool
+sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
+ Sroutine_hash_entry *start)
{
- bool routines_added= TRUE;
+ bool result= FALSE;
- DBUG_ENTER("sp_cache_routines");
+ DBUG_ENTER("sp_cache_routines_and_add_tables_aux");
- while (routines_added)
+ for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
{
- routines_added= FALSE;
+ sp_name name(rt->key.str, rt->key.length);
+ int type= rt->key.str[0];
+ sp_head *sp;
- for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++)
+ if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
+ &thd->sp_func_cache : &thd->sp_proc_cache),
+ &name)))
{
- HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
-
- for (uint i=0 ; i < h->records ; i++)
+ LEX *oldlex= thd->lex;
+ LEX *newlex= new st_lex;
+ thd->lex= newlex;
+ newlex->current_select= NULL;
+ name.m_name.str= strchr(name.m_qname.str, '.');
+ name.m_db.length= name.m_name.str - name.m_qname.str;
+ name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
+ name.m_db.length);
+ name.m_name.str+= 1;
+ name.m_name.length= name.m_qname.length - name.m_db.length - 1;
+
+ if (db_find_routine(thd, type, &name, &sp) == SP_OK)
{
- LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
- sp_name name(*ls);
- sp_head *sp;
-
- name.m_qname= *ls;
- if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
- &thd->sp_func_cache : &thd->sp_proc_cache),
- &name)))
- {
- LEX *oldlex= thd->lex;
- LEX *newlex= new st_lex;
-
- thd->lex= newlex;
- /* Pass hint pointer to mysql.proc table */
- newlex->proc_table= oldlex->proc_table;
- newlex->current_select= NULL;
- name.m_name.str= strchr(name.m_qname.str, '.');
- name.m_db.length= name.m_name.str - name.m_qname.str;
- name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
- name.m_db.length);
- name.m_name.str+= 1;
- name.m_name.length= name.m_qname.length - name.m_db.length - 1;
-
- if (db_find_routine(thd, type, &name, &sp) == SP_OK)
- {
- if (type == TYPE_ENUM_FUNCTION)
- sp_cache_insert(&thd->sp_func_cache, sp);
- else
- sp_cache_insert(&thd->sp_proc_cache, sp);
- }
- delete newlex;
- thd->lex= oldlex;
- }
+ if (type == TYPE_ENUM_FUNCTION)
+ sp_cache_insert(&thd->sp_func_cache, sp);
+ else
+ sp_cache_insert(&thd->sp_proc_cache, sp);
+ }
+ delete newlex;
+ thd->lex= oldlex;
+ }
+ if (sp)
+ {
+ sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines);
+ result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
+ }
+ }
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Cache all routines from the set of used by statement, add tables used
+ by those routines to statement table list. Do the same for all routines
+ used by those routines.
+
+ SYNOPSIS
+ sp_cache_routines_and_add_tables()
+ thd - thread context
+ lex - LEX representing statement
+
+ RETURN VALUE
+ TRUE - some tables were added
+ FALSE - no tables were added.
+*/
+
+bool
+sp_cache_routines_and_add_tables(THD *thd, LEX *lex)
+{
+
+ return sp_cache_routines_and_add_tables_aux(thd, lex,
+ (Sroutine_hash_entry *)lex->sroutines_list.first);
+}
+
+
+/*
+ Add all routines used by view to the set of routines used by statement.
+ Add tables used by those routines to statement table list. Do the same
+ for all routines used by these routines.
+
+ SYNOPSIS
+ sp_cache_routines_and_add_tables_for_view()
+ thd - thread context
+ lex - LEX representing statement
+ aux_lex - LEX representing view
+*/
+
+void
+sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
+{
+ Sroutine_hash_entry **last_cached_routine_ptr=
+ (Sroutine_hash_entry **)lex->sroutines_list.next;
+ sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines);
+ (void)sp_cache_routines_and_add_tables_aux(thd, lex,
+ *last_cached_routine_ptr);
+}
- if (sp)
+
+/*
+ Add triggers for table to the set of routines used by statement.
+ Add tables used by them to statement table list. Do the same for
+ all implicitly used routines.
+
+ SYNOPSIS
+ sp_cache_routines_and_add_tables_for_triggers()
+ thd - thread context
+ lex - LEX respresenting statement
+ triggers - triggers of the table
+*/
+
+void
+sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
+ Table_triggers_list *triggers)
+{
+ if (add_used_routine(lex, thd->current_arena, &triggers->sroutines_key))
+ {
+ Sroutine_hash_entry **last_cached_routine_ptr=
+ (Sroutine_hash_entry **)lex->sroutines_list.next;
+ for (int i= 0; i < 3; i++)
+ for (int j= 0; j < 2; j++)
+ if (triggers->bodies[i][j])
{
- routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns);
- routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs);
+ (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
+ &lex->query_tables_last);
+ sp_update_stmt_used_routines(thd, lex,
+ &triggers->bodies[i][j]->m_sroutines);
}
- }
- }
+
+ (void)sp_cache_routines_and_add_tables_aux(thd, lex,
+ *last_cached_routine_ptr);
}
- DBUG_VOID_RETURN;
}
+
/*
* Generates the CREATE... string from the table information.
* Returns TRUE on success, FALSE on (alloc) failure.
diff --git a/sql/sp.h b/sql/sp.h
index 16d79026132..b8af8d3a321 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -74,20 +74,21 @@ sp_show_create_function(THD *thd, sp_name *name);
int
sp_show_status_function(THD *thd, const char *wild);
-bool
-sp_function_exists(THD *thd, sp_name *name);
-
/*
- * For precaching of functions and procedures
- */
-void
-sp_add_to_hash(HASH *h, sp_name *fun);
-bool
-sp_merge_hash(HASH *dst, HASH *src);
-void
-sp_cache_routines(THD *thd, LEX *lex);
-
+ Procedures for pre-caching of stored routines and building table list
+ for prelocking.
+*/
+void sp_add_used_routine(LEX *lex, Query_arena *arena,
+ sp_name *rt, char rt_type);
+void sp_update_sp_used_routines(HASH *dst, HASH *src);
+bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex);
+void sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
+ LEX *aux_lex);
+void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
+ Table_triggers_list *triggers);
+
+extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
//
// Utilities...
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ee824085df6..02c006d01ee 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -117,7 +117,7 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
DBUG_ENTER("sp_prepare_func_item");
it_addr= it->this_item_addr(thd, it_addr);
- if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr))
+ if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr))
{
DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(NULL);
@@ -242,8 +242,11 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
void
sp_name::init_qname(THD *thd)
{
- m_qname.length= m_db.length+m_name.length+1;
- m_qname.str= thd->alloc(m_qname.length+1);
+ m_sroutines_key.length= m_db.length + m_name.length + 2;
+ if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
+ return;
+ m_qname.length= m_sroutines_key.length - 1;
+ m_qname.str= m_sroutines_key.str + 1;
sprintf(m_qname.str, "%*s.%*s",
m_db.length, (m_db.length ? m_db.str : ""),
m_name.length, m_name.str);
@@ -310,21 +313,19 @@ sp_head::operator delete(void *ptr, size_t size)
sp_head::sp_head()
- :Query_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE),
- m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE)
+ :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
+ m_returns_cs(NULL), m_has_return(FALSE),
+ m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE),
+ m_is_invoked(FALSE)
{
extern byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first);
- extern byte
- *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
- state= INITIALIZED_FOR_SP;
m_backpatch.empty();
m_lex.empty();
hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
- hash_init(&m_spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
- hash_init(&m_spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
+ hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
DBUG_VOID_RETURN;
}
@@ -509,7 +510,7 @@ sp_head::destroy()
delete i;
delete_dynamic(&m_instr);
m_pcont->destroy();
- free_items(free_list);
+ free_items();
/*
If we have non-empty LEX stack then we just came out of parser with
@@ -527,8 +528,7 @@ sp_head::destroy()
}
hash_free(&m_sptabs);
- hash_free(&m_spfuns);
- hash_free(&m_spprocs);
+ hash_free(&m_sroutines);
DBUG_VOID_RETURN;
}
@@ -587,6 +587,28 @@ sp_head::execute(THD *thd)
DBUG_RETURN(-1);
}
+ if (m_is_invoked)
+ {
+ /*
+ We have to disable recursion for stored routines since in
+ many cases LEX structure and many Item's can't be used in
+ reentrant way now.
+
+ TODO: We can circumvent this problem by using separate
+ sp_head instances for each recursive invocation.
+
+ NOTE: Theoretically arguments of procedure can be evaluated
+ before its invocation so there should be no problem with
+ recursion. But since we perform cleanup for CALL statement
+ as for any other statement only after its execution, its LEX
+ structure is not reusable for recursive calls. Thus we have
+ to prohibit recursion for stored procedures too.
+ */
+ my_error(ER_SP_NO_RECURSION, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ m_is_invoked= TRUE;
+
dbchanged= FALSE;
if (m_db.length &&
(ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged)))
@@ -596,7 +618,6 @@ sp_head::execute(THD *thd)
ctx->clear_handler();
thd->query_error= 0;
old_arena= thd->current_arena;
- thd->current_arena= this;
/*
We have to save/restore this info when we are changing call level to
@@ -636,9 +657,24 @@ sp_head::execute(THD *thd)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
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
+ during the first execution (for example expanding of '*' or the
+ items made during other permanent subquery transformations).
+ */
+ 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-
+ statement execution code clears no_send_error between statements too)
+ */
+ thd->net.no_send_error= 0;
if (i->free_list)
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.
@@ -680,8 +716,8 @@ sp_head::execute(THD *thd)
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
- cleanup_items(thd->current_arena->free_list);
thd->current_arena= old_arena;
+ state= EXECUTED;
done:
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
@@ -696,6 +732,7 @@ sp_head::execute(THD *thd)
if (! thd->killed)
ret= sp_change_db(thd, olddb, 0);
}
+ m_is_invoked= FALSE;
DBUG_RETURN(ret);
}
@@ -713,8 +750,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
sp_rcontext *nctx = NULL;
uint i;
int ret;
- MEM_ROOT *old_mem_root, call_mem_root;
- Item *old_free_list, *call_free_list;
+ MEM_ROOT call_mem_root;
+ Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
if (argcount != params)
{
@@ -726,14 +763,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
- old_mem_root= thd->mem_root;
- thd->mem_root= &call_mem_root;
- old_free_list= thd->free_list; // Keep the old list
- thd->free_list= NULL; // Start a new one
+
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize, hmax, cmax);
- nctx->callers_mem_root= old_mem_root;
+ nctx->callers_mem_root= thd->mem_root;
for (i= 0 ; i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
@@ -759,15 +793,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
}
}
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.
- call_free_list= thd->free_list;
- thd->free_list= old_free_list;
- thd->mem_root= old_mem_root;
+ thd->restore_backup_item_arena(&call_arena, &backup_arena);
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
@@ -787,8 +822,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
thd->spcont= octx;
// Now get rid of the rest of the callee context
- cleanup_items(call_free_list);
- free_items(call_free_list);
+ call_arena.free_items();
free_root(&call_mem_root, MYF(0));
DBUG_RETURN(ret);
@@ -820,8 +854,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
- MEM_ROOT *old_mem_root, call_mem_root;
- Item *old_free_list, *call_free_list;
+ MEM_ROOT call_mem_root;
+ Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
if (args->elements != params)
{
@@ -831,10 +865,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
- old_mem_root= thd->mem_root;
- thd->mem_root= &call_mem_root;
- old_free_list= thd->free_list; // Keep the old list
- thd->free_list= NULL; // Start a new one
if (csize > 0 || hmax > 0 || cmax > 0)
{
@@ -899,14 +929,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
if (! ret)
+ {
+ thd->set_n_backup_item_arena(&call_arena, &backup_arena);
ret= execute(thd);
-
- // Partially restore context now.
- // We still need the call mem root and free list for processing
- // of out parameters.
- call_free_list= thd->free_list;
- thd->free_list= old_free_list;
- thd->mem_root= old_mem_root;
+ thd->restore_backup_item_arena(&call_arena, &backup_arena);
+ }
if (!ret && csize > 0)
{
@@ -964,7 +991,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
we do not check suv->fixed, because it can't be fixed after
creation
*/
- suv->fix_fields(thd, NULL, &item);
+ suv->fix_fields(thd, &item);
suv->fix_length_and_dec();
suv->check();
suv->update();
@@ -981,8 +1008,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont= octx;
// Now get rid of the rest of the callee context
- cleanup_items(call_free_list);
- free_items(call_free_list);
+ call_arena.free_items();
thd->lex->unit.cleanup();
free_root(&call_mem_root, MYF(0));
@@ -997,6 +1023,7 @@ sp_head::reset_lex(THD *thd)
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
+ my_lex_states state= oldlex->next_state; // Keep original next_state
(void)m_lex.push_front(oldlex);
thd->lex= sublex= new st_lex;
@@ -1004,6 +1031,11 @@ sp_head::reset_lex(THD *thd)
/* Reset most stuff. The length arguments doesn't matter here. */
lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
+ /*
+ * next_state is normally the same (0), but it happens that we swap lex in
+ * "mid-sentence", so we must restore it.
+ */
+ sublex->next_state= state;
/* We must reset ptr and end_of_query again */
sublex->ptr= oldlex->ptr;
sublex->end_of_query= oldlex->end_of_query;
@@ -1037,11 +1069,10 @@ sp_head::restore_lex(THD *thd)
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
/*
- Add routines which are used by statement to respective sets for
- this routine
+ Add routines which are used by statement to respective set for
+ this routine.
*/
- sp_merge_hash(&m_spfuns, &sublex->spfuns);
- sp_merge_hash(&m_spprocs, &sublex->spprocs);
+ sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines);
/*
Merge tables used by this statement (but not by its functions or
procedures) to multiset of tables used by this routine.
@@ -1276,6 +1307,13 @@ void sp_head::add_instr(sp_instr *instr)
{
instr->free_list= m_thd->free_list;
m_thd->free_list= 0;
+ /*
+ Memory root of every instruction is designated for permanent
+ transformations (optimizations) made on the parsed tree during
+ the first execution. It points to the memory root of the
+ entire stored procedure, as their life span is equal.
+ */
+ instr->mem_root= &main_mem_root;
insert_dynamic(&m_instr, (gptr)&instr);
}
@@ -1470,13 +1508,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
they want to store some value in local variable, pass return value and
etc... So their life time should be longer than one instruction.
- Probably we can call destructors for most of them then we are leaving
- routine. But this won't help much as they are allocated in main query
- MEM_ROOT anyway. So they all go to global thd->free_list.
-
- May be we can use some other MEM_ROOT for this purprose ???
-
- What else should we do for cleanup ?
cleanup_items() is called in sp_head::execute()
*/
return res;
@@ -1578,16 +1609,22 @@ sp_instr_set::print(String *str)
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
- int res= 0;
-
DBUG_ENTER("sp_instr_set_trigger_field::execute");
- /* QQ: Still unsure what should we return in case of error 1 or -1 ? */
- if (!value->fixed && value->fix_fields(thd, 0, &value) ||
- trigger_field->fix_fields(thd, 0, 0) ||
- (value->save_in_field(trigger_field->field, 0) < 0))
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
+{
+ int res= 0;
+ Item *it= sp_prepare_func_item(thd, &value);
+ if (!it ||
+ !trigger_field->fixed && trigger_field->fix_fields(thd, 0) ||
+ (it->save_in_field(trigger_field->field, 0) < 0))
res= -1;
- *nextp= m_ip + 1;
- DBUG_RETURN(res);
+ *nextp = m_ip+1;
+ return res;
}
void
@@ -1938,7 +1975,7 @@ int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_cpush::execute");
- thd->spcont->push_cursor(&m_lex_keeper);
+ thd->spcont->push_cursor(&m_lex_keeper, this);
*nextp= m_ip+1;
DBUG_RETURN(0);
}
@@ -1997,12 +2034,24 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
}
else
{
+ Query_arena *old_arena= thd->current_arena;
+
+ /*
+ Get the Query_arena from the cpush instruction, which contains
+ the free_list of the query, so new items (if any) are stored in
+ the right free_list, and we can cleanup after each open.
+ */
+ thd->current_arena= c->get_instr();
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
+ /* Cleanup the query's items */
+ if (thd->current_arena->free_list)
+ cleanup_items(thd->current_arena->free_list);
+ thd->current_arena= old_arena;
/*
Work around the fact that errors in selects are not returned properly
(but instead converted into a warning), so if a condition handler
caught, we have lost the result code.
- */
+ */
if (!res)
{
uint dummy1, dummy2;
@@ -2399,72 +2448,3 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
return table;
}
-
-/*
- Auxilary function for adding tables used by routines used in query
- to table lists.
-
- SYNOPSIS
- sp_add_sp_tables_to_table_list_aux()
- thd - thread context
- lex - LEX to which table list tables will be added
- func_hash - routines for which tables should be added
- func_cache- SP cache in which this routines should be looked up
-
- NOTE
- See sp_add_sp_tables_to_table_list() for more info.
-
- RETURN VALUE
- TRUE - some tables were added
- FALSE - no tables were added.
-*/
-
-static bool
-sp_add_sp_tables_to_table_list_aux(THD *thd, LEX *lex, HASH *func_hash,
- sp_cache **func_cache)
-{
- uint i;
- bool result= FALSE;
-
- for (i= 0 ; i < func_hash->records ; i++)
- {
- sp_head *sp;
- LEX_STRING *ls= (LEX_STRING *)hash_element(func_hash, i);
- sp_name name(*ls);
-
- name.m_qname= *ls;
- if ((sp= sp_cache_lookup(func_cache, &name)))
- result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
- }
-
- return result;
-}
-
-
-/*
- Add tables used by routines used in query to table list.
-
- SYNOPSIS
- sp_add_sp_tables_to_table_list()
- thd - thread context
- lex - LEX to which table list tables will be added
- func_lex - LEX for which functions we get tables
- (useful for adding tables used by view routines)
-
- NOTE
- Elements of list will be allocated in PS memroot, so this
- list will be persistent between PS execetutions.
-
- RETURN VALUE
- TRUE - some tables were added
- FALSE - no tables were added.
-*/
-
-bool
-sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex)
-{
- return (sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spfuns,
- &thd->sp_func_cache) |
- sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spprocs,
- &thd->sp_proc_cache));
-}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index d22515672f9..32dc4449174 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -48,24 +48,50 @@ public:
LEX_STRING m_db;
LEX_STRING m_name;
LEX_STRING m_qname;
+ /*
+ Key representing routine in the set of stored routines used by statement.
+ Consists of 1-byte routine type and m_qname (which usually refences to
+ same buffer). Note that one must complete initialization of the key by
+ calling set_routine_type().
+ */
+ LEX_STRING m_sroutines_key;
sp_name(LEX_STRING name)
: m_name(name)
{
- m_db.str= m_qname.str= 0;
- m_db.length= m_qname.length= 0;
+ m_db.str= m_qname.str= m_sroutines_key.str= 0;
+ m_db.length= m_qname.length= m_sroutines_key.length= 0;
}
sp_name(LEX_STRING db, LEX_STRING name)
: m_db(db), m_name(name)
{
- m_qname.str= 0;
- m_qname.length= 0;
+ m_qname.str= m_sroutines_key.str= 0;
+ m_qname.length= m_sroutines_key.length= 0;
+ }
+
+ /*
+ Creates temporary sp_name object from key, used mainly
+ for SP-cache lookups.
+ */
+ sp_name(char *key, uint key_len)
+ {
+ m_sroutines_key.str= key;
+ m_sroutines_key.length= key_len;
+ m_name.str= m_qname.str= key + 1;
+ m_name.length= m_qname.length= key_len - 1;
+ m_db.str= 0;
+ m_db.length= 0;
}
// Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation
+ void set_routine_type(char type)
+ {
+ m_sroutines_key.str[0]= type;
+ }
+
~sp_name()
{}
};
@@ -79,6 +105,7 @@ class sp_head :private Query_arena
sp_head(const sp_head &); /* Prevent use of these */
void operator=(sp_head &);
+ MEM_ROOT main_mem_root;
public:
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
@@ -106,13 +133,13 @@ public:
longlong m_created;
longlong m_modified;
/*
- Sets containing names of SP and SF used by this routine.
-
- TODO Probably we should combine these two hashes in one. It will
- decrease memory overhead ans simplify algorithms using them. The
- same applies to similar hashes in LEX.
+ Set containing names of stored routines used by this routine.
+ Note that unlike elements of similar set for statement elements of this
+ set are not linked in one list. Because of this we are able save memory
+ by using for this set same objects that are used in 'sroutines' sets
+ for statements of which this stored routine consists.
*/
- HASH m_spfuns, m_spprocs;
+ HASH m_sroutines;
// Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_body_begin;
@@ -258,6 +285,9 @@ private:
*/
HASH m_sptabs;
+ /* Used for tracking of routine invocations and preventing recursion. */
+ bool m_is_invoked;
+
int
execute(THD *thd);
@@ -273,7 +303,7 @@ private:
// "Instructions"...
//
-class sp_instr : public Sql_alloc
+class sp_instr :public Query_arena, public Sql_alloc
{
sp_instr(const sp_instr &); /* Prevent use of these */
void operator=(sp_instr &);
@@ -281,17 +311,16 @@ class sp_instr : public Sql_alloc
public:
uint marked;
- Item *free_list; // My Items
uint m_ip; // My index
sp_pcontext *m_ctx; // My parse context
// Should give each a name or type code for debugging purposes?
sp_instr(uint ip, sp_pcontext *ctx)
- :Sql_alloc(), marked(0), free_list(0), m_ip(ip), m_ctx(ctx)
+ :Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx)
{}
virtual ~sp_instr()
- { free_items(free_list); }
+ { free_items(); }
// Execute this instrution. '*nextp' will be set to the index of the next
// instruction to execute. (For most instruction this will be the
@@ -471,10 +500,11 @@ class sp_instr_set_trigger_field : public sp_instr
public:
sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
- Item_trigger_field *trg_fld, Item *val)
+ Item_trigger_field *trg_fld,
+ Item *val, LEX *lex)
: sp_instr(ip, ctx),
trigger_field(trg_fld),
- value(val)
+ value(val), m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_set_trigger_field()
@@ -482,11 +512,14 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
private:
Item_trigger_field *trigger_field;
Item *value;
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_trigger_field : public sp_instr
@@ -951,7 +984,5 @@ TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
thr_lock_type locktype);
-bool
-sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex);
#endif /* _SP_HEAD_H_ */
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index aacb9254753..d0817e43790 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -148,9 +148,9 @@ sp_rcontext::restore_variables(uint fp)
}
void
-sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper)
+sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
{
- m_cstack[m_ccount++]= new sp_cursor(lex_keeper);
+ m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
}
void
@@ -169,8 +169,9 @@ sp_rcontext::pop_cursors(uint count)
*
*/
-sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper)
- :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
+sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
+ :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL),
+ m_i(i)
{
/*
currsor can't be stored in QC, so we should prevent opening QC for
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index b188805435f..856beb13f6d 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -26,6 +26,7 @@ struct sp_cond_type;
class sp_cursor;
struct sp_pvar;
class sp_lex_keeper;
+class sp_instr_cpush;
#define SP_HANDLER_NONE 0
#define SP_HANDLER_EXIT 1
@@ -161,7 +162,7 @@ class sp_rcontext : public Sql_alloc
restore_variables(uint fp);
void
- push_cursor(sp_lex_keeper *lex_keeper);
+ push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
void
pop_cursors(uint count);
@@ -203,7 +204,7 @@ class sp_cursor : public Sql_alloc
{
public:
- sp_cursor(sp_lex_keeper *lex_keeper);
+ sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
virtual ~sp_cursor()
{
@@ -229,6 +230,12 @@ public:
int
fetch(THD *, List<struct sp_pvar> *vars);
+ inline sp_instr_cpush *
+ get_instr()
+ {
+ return m_i;
+ }
+
private:
MEM_ROOT m_mem_root; // My own mem_root
@@ -238,6 +245,7 @@ private:
my_bool m_nseof; // Original no_send_eof
Protocol *m_oprot; // Original protcol
MYSQL_ROWS *m_current_row;
+ sp_instr_cpush *m_i; // My push instruction
void
destroy();
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 04da0dd5eb5..04666469e9c 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2035,7 +2035,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
{
uint key_prefix_len;
KEY_PART_INFO *key_part= col_privs->key_info->key_part;
- col_privs->field[0]->store(host.hostname,(uint) strlen(host.hostname),
+ col_privs->field[0]->store(host.hostname,
+ host.hostname ? (uint) strlen(host.hostname) : 0,
system_charset_info);
col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
@@ -2476,7 +2477,6 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
int old_row_exists= 1;
int error=0;
ulong store_proc_rights;
- byte *key;
DBUG_ENTER("replace_routine_table");
if (!initialized)
@@ -3216,7 +3216,6 @@ my_bool grant_init(THD *org_thd)
do
{
GRANT_NAME *mem_check;
- longlong proc_type;
HASH *hash;
if (!(mem_check=new GRANT_NAME(p_table)))
{
@@ -5325,7 +5324,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
Instantiate used templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator<LEX_COLUMN>;
template class List_iterator<LEX_USER>;
template class List<LEX_COLUMN>;
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index f2896889669..eba000a627a 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -106,8 +106,15 @@
(((A) & DB_CHUNK2) >> 6) | \
(((A) & DB_CHUNK3) >> 9) | \
(((A) & DB_CHUNK4) >> 2))
-#define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4))
-#define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4))
+#define TBL_CHUNK0 DB_CHUNK0
+#define TBL_CHUNK1 DB_CHUNK1
+#define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL)
+#define fix_rights_for_table(A) (((A) & TBL_CHUNK0) | \
+ (((A) << 4) & TBL_CHUNK1) | \
+ (((A) << 11) & TBL_CHUNK2))
+#define get_rights_for_table(A) (((A) & TBL_CHUNK0) | \
+ (((A) & TBL_CHUNK1) >> 4) | \
+ (((A) & TBL_CHUNK2) >> 11))
#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8))
#define get_rights_for_column(A) (((A) & 7) | ((A) >> 8))
#define fix_rights_for_procedure(A) ((((A) << 18) & EXECUTE_ACL) | \
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8f83208f44b..7021f61a052 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -542,10 +542,9 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
bool close_thread_table(THD *thd, TABLE **table_ptr)
{
- DBUG_ENTER("close_thread_table");
-
bool found_old_table= 0;
TABLE *table= *table_ptr;
+ DBUG_ENTER("close_thread_table");
DBUG_ASSERT(table->key_read == 0);
DBUG_ASSERT(table->file->inited == handler::NONE);
@@ -972,18 +971,34 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
}
-/******************************************************************************
-** open a table
-** Uses a cache of open tables to find a table not in use.
-** If refresh is a NULL pointer, then the is no version number checking and
-** the table is not put in the thread-open-list
-** If the return value is NULL and refresh is set then one must close
-** all tables and retry the open
-******************************************************************************/
+/*
+ Open a table.
+
+ SYNOPSIS
+ open_table()
+ thd Thread context
+ table_list Open first table in list
+ refresh Pointer to memory that will be set to 1 if
+ we need to close all tables and reopen them
+ If this is a NULL pointer, then the is no version
+ number checking and the table is not put in the
+ thread-open-list
+ flags Bitmap of flags to modify how open works:
+ MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone
+ has done a flush or namelock on it.
+
+ IMPLEMENTATION
+ Uses a cache of open tables to find a table not in use.
+
+ RETURN
+ NULL Open failed. If refresh is set then one should close
+ all other tables and retry the open
+ # Success. Pointer to TABLE object for open table.
+*/
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
- bool *refresh)
+ bool *refresh, uint flags)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
@@ -1026,6 +1041,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->locked_tables || thd->prelocked_mode)
{ // Using table locks
+ TABLE *best_table= 0;
+ int best_distance= INT_MIN, distance;
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->key_length == key_length &&
@@ -1034,11 +1051,37 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->query_id != thd->query_id && /* skip tables already used by this query */
!(thd->prelocked_mode && table->query_id))
{
- table->query_id= thd->query_id;
- DBUG_PRINT("info",("Using locked table"));
- goto reset;
+ 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 still maitain the best_table 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 - we have not enough high lock mode
+ 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)
+ break;
+ }
}
}
+ if (best_table)
+ {
+ table= best_table;
+ table->query_id= thd->query_id;
+ DBUG_PRINT("info",("Using locked table"));
+ goto reset;
+ }
/*
is it view?
(it is work around to allow to open view with locked tables,
@@ -1096,9 +1139,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
if (table->s->version != refresh_version)
{
+ if (flags & MYSQL_LOCK_IGNORE_FLUSH)
+ {
+ /* Force close at once after usage */
+ thd->version= table->s->version;
+ continue;
+ }
+
/*
- ** There is a refresh in progress for this table
- ** Wait until the table is freed or the thread is killed.
+ There is a refresh in progress for this table
+ Wait until the table is freed or the thread is killed.
*/
close_old_data_files(thd,thd->open_tables,0,0);
if (table->in_use != thd)
@@ -1611,8 +1661,18 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
*/
if (discover_retry_count++ != 0)
goto err;
- if (ha_create_table_from_engine(thd, db, name, TRUE) != 0)
+ if (ha_create_table_from_engine(thd, db, name) > 0)
+ {
+ /* Give right error message */
+ thd->clear_error();
+ DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name));
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Failed to open '%-.64s', error while "
+ "unpacking from engine",
+ MYF(0), name);
+
goto err;
+ }
mysql_reset_errors(thd, 1); // Clear warnings
thd->clear_error(); // Clear error message
@@ -1671,6 +1731,15 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (error == 5)
DBUG_RETURN(0); // we have just opened VIEW
+ /*
+ We can't mark all tables in 'mysql' database as system since we don't
+ allow to lock such tables for writing with any other tables (even with
+ other system tables) and some privilege tables need this.
+ */
+ if (!my_strcasecmp(system_charset_info, db, "mysql") &&
+ !my_strcasecmp(system_charset_info, name, "proc"))
+ entry->s->system_table= 1;
+
if (Table_triggers_list::check_n_load(thd, db, name, entry))
goto err;
@@ -1792,16 +1861,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
may be still zero for prelocked statement...
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
- (thd->lex->spfuns.records || thd->lex->spprocs.records))
+ thd->lex->sroutines.records)
{
- TABLE_LIST **save_query_tables_last;
-
- sp_cache_routines(thd, thd->lex);
- save_query_tables_last= thd->lex->query_tables_last;
+ TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
DBUG_ASSERT(thd->lex->query_tables == *start);
- if (sp_add_sp_tables_to_table_list(thd, thd->lex, thd->lex) ||
+ if (sp_cache_routines_and_add_tables(thd, thd->lex) ||
*start)
{
query_tables_last_own= save_query_tables_last;
@@ -1825,7 +1891,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)))
+ !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, 0)))
{
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
if (tables->view)
@@ -1837,19 +1903,16 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
and add tables used by them to table list.
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
- (tables->view->spfuns.records || tables->view->spprocs.records))
+ tables->view->sroutines.records)
{
- // FIXME We should catch recursion for both views and funcs here
- sp_cache_routines(thd, tables->view);
-
/* We have at least one table in TL here */
if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last;
- sp_add_sp_tables_to_table_list(thd, thd->lex, tables->view);
+ sp_cache_routines_and_add_tables_for_view(thd, thd->lex,
+ tables->view);
}
/* Cleanup hashes because destructo for this LEX is never called */
- hash_free(&tables->view->spfuns);
- hash_free(&tables->view->spprocs);
+ hash_free(&tables->view->sroutines);
continue;
}
@@ -1904,9 +1967,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
prelocking list.
If we lock table for reading we won't update it so there is no need to
process its triggers since they never will be activated.
-
- FIXME Now we are simply turning on prelocking. Proper integration
- and testing is to be done later.
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
tables->table->triggers &&
@@ -1914,6 +1974,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
{
if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last;
+ sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
+ tables->table->triggers);
}
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
}
@@ -2000,7 +2062,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
- while (!(table= open_table(thd, table_list, thd->mem_root, &refresh)) &&
+ while (!(table= open_table(thd, table_list, thd->mem_root, &refresh, 0)) &&
refresh)
;
@@ -2397,9 +2459,11 @@ Field *view_ref_found= (Field*) 0x2;
name name of field
item_name name of item if it will be created (VIEW)
length length of name
- ref expression substituted in VIEW should be
+ 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?
@@ -2429,20 +2493,13 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
table_list->alias, name, item_name, (ulong) ref));
if (table_list->field_translation)
{
- uint num;
- if (table_list->schema_table_reformed)
- {
- num= thd->lex->current_select->item_list.elements;
- }
- else
- {
- DBUG_ASSERT(ref != 0 && table_list->view != 0);
- num= table_list->view->select_lex.item_list.elements;
- }
- Field_translator *trans= table_list->field_translation;
- for (uint i= 0; i < num; i ++)
+ 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, trans[i].name, name))
+ if (!my_strcasecmp(system_charset_info, field_it.name(), name))
{
if (table_list->schema_table_reformed)
{
@@ -2452,7 +2509,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
So we can return ->field. It is used only for
'show & where' commands.
*/
- DBUG_RETURN(((Item_field*) (trans[i].item))->field);
+ DBUG_RETURN(((Item_field*) (field_it.item()))->field);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants_view &&
@@ -2462,26 +2519,23 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
name, length))
DBUG_RETURN(WRONG_GRANT);
#endif
- if (thd->lex->current_select->no_wrap_view_item)
- {
- if (register_tree_change)
- thd->change_item_tree(ref, trans[i].item);
- else
- *ref= trans[i].item;
- }
- else
+ Item *item= field_it.create_item(thd);
+ if (!item)
{
- Item_ref *item_ref= new Item_ref(&trans[i].item,
- table_list->view_name.str,
- item_name);
- /* as far as Item_ref have defined reference it do not need tables */
- if (register_tree_change && item_ref)
- thd->change_item_tree(ref, item_ref);
- else if (item_ref)
- *ref= item_ref;
- if (!(*ref)->fixed)
- (*ref)->fix_fields(thd, 0, ref);
+ 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);
}
}
@@ -2589,19 +2643,21 @@ 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
- point to the found view field
- 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
- - REPORT_EXCEPT_NON_UNIQUE report all other errors
- except when non-unique fields were found
- - REPORT_ALL_ERRORS
- check_privileges need to check privileges
+ 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
+ point to the found view field
+ 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
+ - 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
RETURN VALUES
0 If error: the found field is not unique, or there are
@@ -2617,7 +2673,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
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 check_privileges, bool register_tree_change)
{
Field *found=0;
const char *db=item->db_name;
@@ -2625,7 +2681,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
const char *name=item->field_name;
uint length=(uint) strlen(name);
char name_buff[NAME_LEN+1];
-
+ bool allow_rowid;
if (item->cached_table)
{
@@ -2660,7 +2716,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
(test(table->grant.want_privilege) &&
check_privileges),
1, &(item->cached_field_index),
- TRUE);
+ register_tree_change);
}
if (found)
{
@@ -2695,7 +2751,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (table_name && table_name[0])
{ /* Qualified field */
- bool found_table=0;
+ bool found_table= 0;
for (; tables; tables= tables->next_local)
{
/* TODO; Ensure that db and tables->db always points to something ! */
@@ -2713,7 +2769,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
(test(tables->grant.want_privilege) &&
check_privileges),
1, &(item->cached_field_index),
- TRUE);
+ register_tree_change);
if (find)
{
item->cached_table= tables;
@@ -2756,10 +2812,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) not_found_field;
return (Field*) 0;
}
-
- bool allow_rowid= tables && !tables->next_local; // Only one table
+ 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 ||
@@ -2768,17 +2824,17 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) not_found_field;
}
- Field *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),
- TRUE);
+ 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)
{
if (field == WRONG_GRANT)
@@ -2793,7 +2849,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
return (Field*) 0;
}
- found=field;
+ found= field;
}
}
if (found)
@@ -3049,9 +3105,10 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
it.replace(new Item_int("Not_used", (longlong) 1, 21));
}
- else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
+ else if (insert_fields(thd, ((Item_field*) item)->context,
+ ((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it,
- any_privileges, arena != 0))
+ any_privileges))
{
if (arena)
thd->restore_backup_item_arena(arena, &backup);
@@ -3085,7 +3142,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
** Check that all given fields exists and fill struct with current data
****************************************************************************/
-bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+bool setup_fields(THD *thd, Item **ref_pointer_array,
List<Item> &fields, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func)
{
@@ -3114,7 +3171,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **ref= ref_pointer_array;
while ((item= it++))
{
- if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
+ if (!item->fixed && item->fix_fields(thd, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
DBUG_RETURN(TRUE); /* purecov: inspected */
@@ -3164,6 +3221,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
SYNOPSIS
setup_tables()
thd Thread handler
+ context name resolution contest to setup table list there
tables Table list
conds Condition of current SELECT (can be changed by VIEW)
leaves List of join table leaves list
@@ -3183,11 +3241,15 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
TRUE error
*/
-bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
+bool setup_tables(THD *thd, Name_resolution_context *context,
+ TABLE_LIST *tables, Item **conds,
TABLE_LIST **leaves, bool select_insert)
{
uint tablenr= 0;
DBUG_ENTER("setup_tables");
+
+ context->table_list= tables;
+
/*
this is used for INSERT ... SELECT.
For select we setup tables except first (and its underlying tables)
@@ -3242,10 +3304,21 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
table_list;
table_list= table_list->next_local)
{
- if (table_list->ancestor &&
- table_list->setup_ancestor(thd, conds,
- table_list->effective_with_check))
- DBUG_RETURN(1);
+ if (table_list->ancestor)
+ {
+ DBUG_ASSERT(table_list->view);
+ Query_arena *arena= thd->current_arena, backup;
+ bool res;
+ if (arena->is_conventional())
+ arena= 0; // For easier test
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
+ res= table_list->setup_ancestor(thd);
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (res)
+ DBUG_RETURN(1);
+ }
}
DBUG_RETURN(0);
}
@@ -3297,15 +3370,13 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
SYNOPSIS
insert_fields()
thd Thread handler
- tables List of tables
+ context Context for name resolution
db_name Database name in case of 'database_name.table_name.*'
table_name Table name in case of 'table_name.*'
it Pointer to '*'
any_privileges 0 If we should ensure that we have SELECT privileges
for all columns
1 If any privilege is ok
- allocate_view_names if true view names will be copied to current Query_arena
- memory (made for SP/PS)
RETURN
0 ok
'it' is updated to point at last inserted
@@ -3313,9 +3384,9 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
*/
bool
-insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
+insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
const char *table_name, List_iterator<Item> *it,
- bool any_privileges, bool allocate_view_names)
+ bool any_privileges)
{
/* allocate variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
@@ -3337,7 +3408,9 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
}
found= 0;
- for (; tables; tables= tables->next_local)
+ for (TABLE_LIST *tables= context->table_list;
+ tables;
+ tables= tables->next_local)
{
Field_iterator *iterator;
TABLE_LIST *natural_join_table;
@@ -3346,7 +3419,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
TABLE_LIST *last;
TABLE_LIST *embedding;
TABLE *table= tables->table;
- bool alias_used= 0;
if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
tables->alias) &&
@@ -3380,16 +3452,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
}
}
#endif
- if (table)
- thd->used_tables|= table->map;
- else
- {
- view_iter.set(tables);
- for (; !view_iter.end_of_fields(); view_iter.next())
- {
- thd->used_tables|= view_iter.item(thd)->used_tables();
- }
- }
natural_join_table= 0;
last= embedded= tables;
@@ -3420,8 +3482,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
{
iterator= &view_iter;
view= 1;
- alias_used= my_strcasecmp(table_alias_charset,
- tables->table_name, tables->alias);
}
else
{
@@ -3430,6 +3490,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
}
iterator->set(tables);
+ /* for view used tables will be collected in following loop */
+ if (table)
+ thd->used_tables|= table->map;
+
for (; !iterator->end_of_fields(); iterator->next())
{
Item *not_used_item;
@@ -3442,16 +3506,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
strlen(field_name), &not_used_item, 0, 0, 0,
&not_used_field_index, TRUE))
{
- Item *item= iterator->item(thd);
- if (view && !thd->lex->current_select->no_wrap_view_item)
- {
- /*
- as far as we have view, then item point to view_iter, so we
- can use it directly for this view specific operation
- */
- item= new Item_ref(view_iter.item_ptr(), tables->view_name.str,
- field_name);
- }
+ Item *item= iterator->create_item(thd);
+ if (!item)
+ goto err;
+ thd->used_tables|= item->used_tables();
if (!found++)
(void) it->replace(item); // Replace '*'
else
@@ -3506,24 +3564,11 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
field->query_id=thd->query_id;
table->used_keys.intersect(field->part_of_key);
}
- else if (allocate_view_names &&
- thd->lex->current_select->first_execution)
+ else
{
- Item_field *item;
- if (alias_used)
- item= new Item_field(0,
- thd->strdup(tables->alias),
- thd->strdup(field_name));
- else
- item= new Item_field(thd->strdup(tables->view_db.str),
- thd->strdup(tables->view_name.str),
- thd->strdup(field_name));
- /*
- during cleunup() this item will be put in list to replace
- expression from VIEW
- */
- thd->nocheck_register_item_tree_change(it->ref(), item,
- thd->mem_root);
+ Item *item= ((Field_iterator_view *) iterator)->item();
+ item->walk(&Item::reset_query_id_processor,
+ (byte *)(&thd->query_id));
}
}
/*
@@ -3541,9 +3586,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_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);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
err:
-#endif
DBUG_RETURN(1);
}
@@ -3554,16 +3597,25 @@ err:
SYNOPSIS
setup_conds()
thd thread handler
- tables list of tables for name resolving
leaves list of leaves of join table tree
*/
-int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
+ COND **conds)
{
SELECT_LEX *select_lex= thd->lex->current_select;
Query_arena *arena= thd->current_arena, backup;
- bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
TABLE_LIST *table= NULL; // For HP compilers
+ /*
+ it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
+ which belong to LEX, i.e. most up SELECT) will be updated by
+ INSERT/UPDATE/LOAD
+ NOTE: using this condition helps to prevent call of prepare_check_option()
+ from subquery of VIEW, because tables of subquery belongs to VIEW
+ (see condition before prepare_check_option() call)
+ */
+ bool it_is_update= (select_lex == &thd->lex->select_lex) &&
+ thd->lex->which_check_option_applicable();
DBUG_ENTER("setup_conds");
if (select_lex->conds_processed_with_permanent_arena ||
@@ -3572,12 +3624,17 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->set_query_id=1;
- thd->lex->current_select->no_wrap_view_item= 0;
+ for (table= tables; table; table= table->next_local)
+ {
+ if (table->prepare_where(thd, conds, FALSE))
+ goto err_no_arena;
+ }
+
select_lex->cond_count= 0;
if (*conds)
{
thd->where="where clause";
- if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) ||
+ if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) ||
(*conds)->check_cols(1))
goto err_no_arena;
}
@@ -3595,11 +3652,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
/* Make a join an a expression */
thd->where="on clause";
if (!embedded->on_expr->fixed &&
- embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) ||
+ embedded->on_expr->fix_fields(thd, &embedded->on_expr) ||
embedded->on_expr->check_cols(1))
goto err_no_arena;
select_lex->cond_count++;
}
+
if (embedded->natural_join)
{
/* Make a join of all fields wich have the same name */
@@ -3679,7 +3737,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{
if (t2_field != view_ref_found)
{
- if (!(item_t2= new Item_field(thd, t2_field)))
+ 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;
@@ -3691,7 +3750,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
t1_field->query_id= thd->query_id;
t1->used_keys.intersect(t1_field->part_of_key);
}
- Item_func_eq *tmp= new Item_func_eq(iterator->item(thd),
+ Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd),
item_t2);
if (!tmp)
goto err;
@@ -3707,7 +3766,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{
COND *on_expr= cond_and;
if (!on_expr->fixed)
- on_expr->fix_fields(thd, 0, &on_expr);
+ on_expr->fix_fields(thd, &on_expr);
if (!embedded->outer_join) // Not left join
{
*conds= and_conds(*conds, cond_and);
@@ -3716,7 +3775,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed)
{
- if ((*conds)->fix_fields(thd, tables, conds))
+ if ((*conds)->fix_fields(thd, conds))
goto err_no_arena;
}
}
@@ -3728,8 +3787,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (embedded->on_expr && !embedded->on_expr->fixed)
{
- if (embedded->on_expr->fix_fields(thd, tables,
- &embedded->on_expr))
+ if (embedded->on_expr->fix_fields(thd, &embedded->on_expr))
goto err_no_arena;
}
}
@@ -3741,6 +3799,20 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
}
while (embedding &&
embedding->nested_join->join_list.head() == embedded);
+
+ /* process CHECK OPTION */
+ if (it_is_update)
+ {
+ TABLE_LIST *view= table->belong_to_view;
+ if (!view)
+ view= table;
+ if (view->effective_with_check)
+ {
+ if (view->prepare_check_option(thd))
+ goto err_no_arena;
+ thd->change_item_tree(&table->check_option, view->check_option);
+ }
+ }
}
if (!thd->current_arena->is_conventional())
@@ -3754,14 +3826,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
select_lex->where= *conds;
select_lex->conds_processed_with_permanent_arena= 1;
}
- thd->lex->current_select->no_wrap_view_item= save_wrapper;
DBUG_RETURN(test(thd->net.report_error));
err:
if (arena)
thd->restore_backup_item_arena(arena, &backup);
err_no_arena:
- thd->lex->current_select->no_wrap_view_item= save_wrapper;
DBUG_RETURN(1);
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 430e0fbcabf..e0a15b7d449 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -278,7 +278,6 @@ TODO list:
- Move MRG_MYISAM table type processing to handlers, something like:
tables_used->table->file->register_used_filenames(callback,
first_argument);
- - Make derived tables cachable.
- QC improvement suggested by Monty:
- Add a counter in open_table() for how many MERGE (ISAM or MyISAM)
tables are cached in the table cache.
@@ -2135,6 +2134,13 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
tables_used;
tables_used= tables_used->next_global, n++, block_table++)
{
+ if (tables_used->derived)
+ {
+ DBUG_PRINT("qcache", ("derived table skipped"));
+ n--;
+ block_table--;
+ continue;
+ }
block_table->n= n;
if (tables_used->view)
{
@@ -2778,6 +2784,12 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
tables_used->table->s->table_name,
tables_used->table->s->table_cache_key,
tables_used->table->s->db_type));
+ if (tables_used->derived)
+ {
+ table_count--;
+ DBUG_PRINT("qcache", ("derived table skipped"));
+ continue;
+ }
*tables_type|= tables_used->table->file->table_cache_type();
/*
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 299011d8821..d0ac1a16f6b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -49,7 +49,7 @@ char internal_table_name[2]= "*";
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class List<Key>;
template class List_iterator<Key>;
@@ -157,17 +157,29 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
+Open_tables_state::Open_tables_state()
+ :version(refresh_version)
+{
+ reset_open_tables_state();
+}
+
+
+/*
+ Pass nominal parameters to Statement constructor only to ensure that
+ the destructor works OK in case of error. The main_mem_root will be
+ re-initialized in init().
+*/
+
THD::THD()
- :user_time(0), global_read_lock(0), is_fatal_error(0),
+ :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
+ Open_tables_state(),
+ user_time(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),
spcont(NULL)
{
current_arena= this;
-#ifndef DBUG_OFF
- backup_arena= 0;
-#endif
host= user= priv_user= db= ip= 0;
catalog= (char*)"std"; // the only catalog we have for now
host_or_ip= "connecting host";
@@ -178,10 +190,8 @@ THD::THD()
db_length= col_access=0;
query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
- open_tables= temporary_tables= handler_tables= derived_tables= 0;
hash_clear(&handler_tables_hash);
tmp_table=0;
- lock=locked_tables=0;
used_tables=0;
cuted_fields= sent_row_count= 0L;
limit_found_rows= 0;
@@ -227,7 +237,6 @@ THD::THD()
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access=NO_ACCESS;
#endif
- version=refresh_version; // For boot
*scramble= '\0';
init();
@@ -256,7 +265,6 @@ THD::THD()
tablespace_op=FALSE;
ulong tmp=sql_rnd_with_mutex();
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
- prelocked_mode= NON_PRELOCKED;
}
@@ -279,6 +287,8 @@ void THD::init(void)
#endif
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
+ if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
+ server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
options= thd_startup_options;
open_options=ha_open_options;
update_lock_default= (variables.low_priority_updates ?
@@ -420,8 +430,6 @@ THD::~THD()
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
- /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
- clear_alloc_root(&stmt_backup.main_mem_root);
DBUG_VOID_RETURN;
}
@@ -524,7 +532,7 @@ void THD::cleanup_after_query()
next_insert_id= 0;
}
/* Free Items that were created during this execution */
- free_items(free_list);
+ free_items();
/*
In the rest of code we assume that free_list never points to garbage:
Keep this predicate true.
@@ -783,7 +791,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
void *change_mem= alloc_root(runtime_memroot, sizeof(*change));
if (change_mem == 0)
{
- fatal_error();
+ /*
+ OOM, thd->fatal_error() is called by the error handler of the
+ memroot. Just return.
+ */
return;
}
change= new (change_mem) Item_change_record;
@@ -1450,17 +1461,16 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
(void)local_vars.push_back(new Item_splocal(mv->s, mv->offset));
else
{
- Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item);
+ Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item);
/*
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
Item_func_set_user_var can't be fixed after creation, so we do not
- check xx->fixed
+ check var->fixed
*/
- xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first,
- 0);
- xx->fix_length_and_dec();
- vars.push_back(xx);
+ var->fix_fields(thd, 0);
+ var->fix_length_and_dec();
+ vars.push_back(var);
}
}
return 0;
@@ -1474,56 +1484,25 @@ void select_dumpvar::cleanup()
}
-/*
- Create arena for already constructed THD.
-
- SYNOPSYS
- Query_arena()
- thd - thread for which arena is created
-
- DESCRIPTION
- Create arena for already existing THD using its variables as parameters
- for memory root initialization.
-*/
-Query_arena::Query_arena(THD* thd)
- :free_list(0), mem_root(&main_mem_root),
- state(INITIALIZED)
-{
- init_sql_alloc(&main_mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
-}
-
-
-/*
- Create arena and optionally initialize memory root.
-
- SYNOPSYS
- Query_arena()
- init_mem_root - whenever we need to initialize memory root
-
- DESCRIPTION
- Create arena and optionally initialize memory root with minimal
- possible parameters.
-
- NOTE
- We use this constructor when arena is part of THD, but reinitialize
- its memory root in THD::init_for_queries() before execution of real
- statements.
-*/
-Query_arena::Query_arena(bool init_mem_root)
- :free_list(0), mem_root(&main_mem_root),
- state(CONVENTIONAL_EXECUTION)
+Query_arena::Type Query_arena::type() const
{
- if (init_mem_root)
- init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ DBUG_ASSERT(0); /* Should never be called */
+ return STATEMENT;
}
-Query_arena::Type Query_arena::type() const
+void Query_arena::free_items()
{
- DBUG_ASSERT(0); /* Should never be called */
- return STATEMENT;
+ Item *next;
+ DBUG_ENTER("Query_arena::free_items");
+ /* This works because items are allocated with sql_alloc() */
+ for (; free_list; free_list= next)
+ {
+ next= free_list->next;
+ free_list->delete_self();
+ }
+ /* Postcondition: free_list is 0 */
+ DBUG_VOID_RETURN;
}
@@ -1531,9 +1510,10 @@ Query_arena::Type Query_arena::type() const
Statement functions
*/
-Statement::Statement(THD *thd)
- :Query_arena(thd),
- id(++thd->statement_id_counter),
+Statement::Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size)
+ :Query_arena(&main_mem_root, state_arg),
+ id(id_arg),
set_query_id(1),
allow_sum_func(0),
lex(&main_lex),
@@ -1542,24 +1522,7 @@ Statement::Statement(THD *thd)
cursor(0)
{
name.str= NULL;
-}
-
-/*
- This constructor is called when statement is a subobject of THD:
- Some variables are initialized in THD::init due to locking problems
- This statement object will be used to
-*/
-
-Statement::Statement()
- :Query_arena((bool)TRUE),
- id(0),
- set_query_id(1),
- allow_sum_func(0), /* initialized later */
- lex(&main_lex),
- query(0), /* these two are set */
- query_length(0), /* in alloc_query() */
- cursor(0)
-{
+ init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size);
}
@@ -1584,15 +1547,19 @@ void Statement::set_statement(Statement *stmt)
void
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
{
+ DBUG_ENTER("Statement::set_n_backup_statement");
backup->set_statement(this);
set_statement(stmt);
+ DBUG_VOID_RETURN;
}
void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
{
+ DBUG_ENTER("Statement::restore_backup_statement");
stmt->set_statement(this);
set_statement(backup);
+ DBUG_VOID_RETURN;
}
@@ -1614,11 +1581,12 @@ void THD::end_statement()
void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup)
{
DBUG_ENTER("Query_arena::set_n_backup_item_arena");
- DBUG_ASSERT(backup_arena == 0);
+ DBUG_ASSERT(backup->is_backup_arena == FALSE);
+
backup->set_item_arena(this);
set_item_arena(set);
#ifndef DBUG_OFF
- backup_arena= 1;
+ backup->is_backup_arena= TRUE;
#endif
DBUG_VOID_RETURN;
}
@@ -1627,20 +1595,11 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup)
void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup)
{
DBUG_ENTER("Query_arena::restore_backup_item_arena");
+ DBUG_ASSERT(backup->is_backup_arena);
set->set_item_arena(this);
set_item_arena(backup);
#ifndef DBUG_OFF
- backup_arena= 0;
-#endif
-#ifdef NOT_NEEDED_NOW
- /*
- Reset backup mem_root to avoid its freeing.
- Since Query_arena's mem_root is freed only when it is part of Statement
- we need this only if we use some Statement's arena as backup storage.
- But we do this only with THD::stmt_backup and this Statement is specially
- handled in this respect. So this code is not really needed now.
- */
- clear_alloc_root(&backup->mem_root);
+ backup->is_backup_arena= FALSE;
#endif
DBUG_VOID_RETURN;
}
@@ -1654,6 +1613,11 @@ void Query_arena::set_item_arena(Query_arena *set)
Statement::~Statement()
{
+ /*
+ We must free `main_mem_root', not `mem_root' (pointer), to work
+ correctly if this statement is used as a backup statement,
+ for which `mem_root' may point to some other statement.
+ */
free_root(&main_mem_root, MYF(0));
}
@@ -1816,3 +1780,40 @@ void THD::set_status_var_init()
{
bzero((char*) &status_var, sizeof(status_var));
}
+
+/****************************************************************************
+ Handling of open and locked tables states.
+
+ This is used when we want to open/lock (and then close) some tables when
+ we already have a set of tables open and locked. We use these methods for
+ access to mysql.proc table to find definitions of stored routines.
+****************************************************************************/
+
+bool THD::push_open_tables_state()
+{
+ 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
+ reset_open_tables_state();
+ DBUG_RETURN(0);
+}
+
+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);
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 24039a9c916..6c4315b95fa 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -653,6 +653,14 @@ typedef struct system_status_var
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
+#endif
+
+
class Query_arena
{
public:
@@ -661,10 +669,9 @@ public:
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
- MEM_ROOT main_mem_root;
MEM_ROOT *mem_root; // Pointer to current memroot
#ifndef DBUG_OFF
- bool backup_arena;
+ bool is_backup_arena; /* True if this arena is used for backup. */
#endif
enum enum_state
{
@@ -680,25 +687,21 @@ public:
STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
};
+ Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) :
+ free_list(0), mem_root(mem_root_arg), state(state_arg)
+ { INIT_ARENA_DBUG_INFO; }
/*
This constructor is used only when Query_arena is created as
backup storage for another instance of Query_arena.
*/
- Query_arena() {};
- /*
- Create arena for already constructed THD using its variables as
- parameters for memory root initialization.
- */
- Query_arena(THD *thd);
- /*
- Create arena and optionally init memory root with minimal values.
- Particularly used if Query_arena is part of Statement.
- */
- Query_arena(bool init_mem_root);
+ Query_arena() { INIT_ARENA_DBUG_INFO; }
+
virtual Type type() const;
virtual ~Query_arena() {};
inline bool is_stmt_prepare() const { return state == INITIALIZED; }
+ inline bool is_first_sp_execute() const
+ { return state == INITIALIZED_FOR_SP; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
@@ -706,6 +709,7 @@ public:
{ return state == PREPARED || state == EXECUTED; }
inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; }
+
inline gptr alloc(unsigned int size) { return alloc_root(mem_root,size); }
inline gptr calloc(unsigned int size)
{
@@ -731,6 +735,8 @@ public:
void set_n_backup_item_arena(Query_arena *set, Query_arena *backup);
void restore_backup_item_arena(Query_arena *set, Query_arena *backup);
void set_item_arena(Query_arena *set);
+
+ void free_items();
};
@@ -755,7 +761,8 @@ class Statement: public Query_arena
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
public:
- /* FIXME: must be private */
+ /* FIXME: these must be protected */
+ MEM_ROOT main_mem_root;
LEX main_lex;
/*
@@ -813,13 +820,11 @@ public:
public:
- /*
- This constructor is called when statement is a subobject of THD:
- some variables are initialized in THD::init due to locking problems
- */
- Statement();
+ /* This constructor is called for backup statements */
+ Statement() { clear_alloc_root(&main_mem_root); }
- Statement(THD *thd);
+ Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size);
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
@@ -928,12 +933,93 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
/*
+ Class that holds information about tables which were open and locked
+ by the thread. It is also used to save/restore this information in
+ push_open_tables_state()/pop_open_tables_state().
+*/
+
+class Open_tables_state
+{
+public:
+ /*
+ open_tables - list of regular tables in use by this thread
+ temporary_tables - list of temp tables in use by this thread
+ handler_tables - list of tables that were opened with HANDLER OPEN
+ and are still in use by this thread
+ */
+ TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables;
+ /*
+ During a MySQL session, one can lock tables in two modes: automatic
+ or manual. In automatic mode all necessary tables are locked just before
+ statement execution, and all acquired locks are stored in 'lock'
+ member. Unlocking takes place automatically as well, when the
+ statement ends.
+ Manual mode comes into play when a user issues a 'LOCK TABLES'
+ statement. In this mode the user can only use the locked tables.
+ Trying to use any other tables will give an error. The locked tables are
+ stored in 'locked_tables' member. Manual locking is described in
+ the 'LOCK_TABLES' chapter of the MySQL manual.
+ See also lock_tables() for details.
+ */
+ MYSQL_LOCK *lock;
+ /*
+ Tables that were locked with explicit or implicit LOCK TABLES.
+ (Implicit LOCK TABLES happens when we are prelocking tables for
+ execution of statement which uses stored routines. See description
+ THD::prelocked_mode for more info.)
+ */
+ MYSQL_LOCK *locked_tables;
+ /*
+ prelocked_mode_type enum and prelocked_mode member are used for
+ indicating whenever "prelocked mode" is on, and what type of
+ "prelocked mode" is it.
+
+ Prelocked mode is used for execution of queries which explicitly
+ or implicitly (via views or triggers) use functions, thus may need
+ some additional tables (mentioned in query table list) for their
+ execution.
+
+ First open_tables() call for such query will analyse all functions
+ used by it and add all additional tables to table its list. It will
+ also mark this query as requiring prelocking. After that lock_tables()
+ will issue implicit LOCK TABLES for the whole table list and change
+ thd::prelocked_mode to non-0. All queries called in functions invoked
+ by the main query will use prelocked tables. Non-0 prelocked_mode
+ will also surpress mentioned analysys in those queries thus saving
+ cycles. Prelocked mode will be turned off once close_thread_tables()
+ for the main query will be called.
+
+ Note: Since not all "tables" present in table list are really locked
+ thd::prelocked_mode does not imply thd::locked_tables.
+ */
+ prelocked_mode_type prelocked_mode;
+ ulong version;
+ uint current_tablenr;
+
+ Open_tables_state();
+
+ void set_open_tables_state(Open_tables_state *state)
+ {
+ *this= *state;
+ }
+
+ void reset_open_tables_state()
+ {
+ open_tables= temporary_tables= handler_tables= derived_tables= 0;
+ lock= locked_tables= 0;
+ prelocked_mode= NON_PRELOCKED;
+ }
+};
+
+
+/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
class THD :public ilink,
- public Statement
+ public Statement,
+ public Open_tables_state
{
public:
#ifdef EMBEDDED_LIBRARY
@@ -962,11 +1048,6 @@ public:
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
- keeps THD state while it is used for active statement
- Note: we perform special cleanup for it in THD destructor.
- */
- Statement stmt_backup;
- /*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
*/
@@ -1006,34 +1087,6 @@ public:
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
- /*
- open_tables - list of regular tables in use by this thread
- temporary_tables - list of temp tables in use by this thread
- handler_tables - list of tables that were opened with HANDLER OPEN
- and are still in use by this thread
- */
- TABLE *open_tables,*temporary_tables, *handler_tables, *derived_tables;
- /*
- During a MySQL session, one can lock tables in two modes: automatic
- or manual. In automatic mode all necessary tables are locked just before
- statement execution, and all acquired locks are stored in 'lock'
- member. Unlocking takes place automatically as well, when the
- statement ends.
- Manual mode comes into play when a user issues a 'LOCK TABLES'
- statement. In this mode the user can only use the locked tables.
- Trying to use any other tables will give an error. The locked tables are
- stored in 'locked_tables' member. Manual locking is described in
- the 'LOCK_TABLES' chapter of the MySQL manual.
- See also lock_tables() for details.
- */
- MYSQL_LOCK *lock; /* Current locks */
- /*
- Tables that were locked with explicit or implicit LOCK TABLES.
- (Implicit LOCK TABLES happens when we are prelocking tables for
- execution of statement which uses stored routines. See description
- THD::prelocked_mode for more info.)
- */
- MYSQL_LOCK *locked_tables;
HASH handler_tables_hash;
/*
One thread can hold up to one named user-level lock. This variable
@@ -1046,7 +1099,7 @@ public:
#endif
struct st_my_thread_var *mysys_var;
/*
- Type of current query: COM_PREPARE, COM_QUERY, etc. Set from
+ Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from
first byte of the packet in do_command()
*/
enum enum_server_command command;
@@ -1109,12 +1162,22 @@ public:
This is to track items changed during execution of a prepared
statement/stored procedure. It's created by
register_item_tree_change() in memory root of THD, and freed in
- rollback_item_tree_changes(). For conventional execution it's always 0.
+ rollback_item_tree_changes(). For conventional execution it's always
+ empty.
*/
Item_change_list change_list;
/*
- Current prepared Query_arena if there one, or 0
+ A permanent memory area of the statement. For conventional
+ execution, the parsed tree and execution runtime reside in the same
+ memory root. In this case current_arena points to THD. In case of
+ a prepared statement or a stored procedure statement, thd->mem_root
+ conventionally points to runtime memory, and thd->current_arena
+ points to the memory of the PS/SP, where the parsed tree of the
+ statement resides. Whenever you need to perform a permanent
+ transformation of a parsed tree, you should allocate new memory in
+ current_arena, to allow correct re-execution of PS/SP.
+ Note: in the parser, current_arena == thd, even for PS/SP.
*/
Query_arena *current_arena;
/*
@@ -1150,6 +1213,7 @@ 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.
@@ -1159,7 +1223,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id, warn_id;
- ulong version, options, thread_id, col_access;
+ ulong options, thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
@@ -1167,7 +1231,7 @@ public:
ulong row_count; // Row counter, mainly for errors and warnings
long dbug_thread_id;
pthread_t real_id;
- uint current_tablenr,tmp_table,global_read_lock;
+ uint tmp_table, global_read_lock;
uint server_status,open_options,system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
@@ -1218,31 +1282,6 @@ public:
long long_value;
} sys_var_tmp;
- /*
- prelocked_mode_type enum and prelocked_mode member are used for
- indicating whenever "prelocked mode" is on, and what type of
- "prelocked mode" is it.
-
- Prelocked mode is used for execution of queries which explicitly
- or implicitly (via views or triggers) use functions, thus may need
- some additional tables (mentioned in query table list) for their
- execution.
-
- First open_tables() call for such query will analyse all functions
- used by it and add all additional tables to table its list. It will
- also mark this query as requiring prelocking. After that lock_tables()
- will issue implicit LOCK TABLES for the whole table list and change
- thd::prelocked_mode to non-0. All queries called in functions invoked
- by the main query will use prelocked tables. Non-0 prelocked_mode
- will also surpress mentioned analysys in those queries thus saving
- cycles. Prelocked mode will be turned off once close_thread_tables()
- for the main query will be called.
-
- Note: Since not all "tables" present in table list are really locked
- thd::relocked_mode does not imply thd::locked_tables.
- */
- prelocked_mode_type prelocked_mode;
-
THD();
~THD();
@@ -1338,13 +1377,9 @@ public:
return 0;
#endif
}
- inline bool only_prepare()
- {
- return command == COM_PREPARE;
- }
inline bool fill_derived_tables()
{
- return !only_prepare() && !lex->only_view_structure();
+ return !current_arena->is_stmt_prepare() && !lex->only_view_structure();
}
inline gptr trans_alloc(unsigned int size)
{
@@ -1390,7 +1425,7 @@ public:
already changed to use this arena.
*/
if (!current_arena->is_conventional() &&
- mem_root != &current_arena->main_mem_root)
+ mem_root != current_arena->mem_root)
{
set_n_backup_item_arena(current_arena, backup);
return current_arena;
@@ -1432,13 +1467,18 @@ public:
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
}
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();
};
+
#define tmp_disable_binlog(A) \
- ulong save_options= (A)->options; \
- (A)->options&= ~OPTION_BIN_LOG;
+ {ulong tmp_disable_binlog__save_options= (A)->options; \
+ (A)->options&= ~OPTION_BIN_LOG
-#define reenable_binlog(A) (A)->options= save_options;
+#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
/* Flags for the THD::system_thread (bitmap) variable */
#define SYSTEM_THREAD_DELAYED_INSERT 1
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d782744162d..d83937098e2 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -300,7 +300,9 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
- if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) ||
+ if (setup_tables(thd, &thd->lex->select_lex.context,
+ table_list, conds, &select_lex->leaf_tables,
+ FALSE) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
@@ -356,7 +358,8 @@ bool mysql_multi_delete_prepare(THD *thd)
lex->query_tables also point on local list of DELETE SELECT_LEX
*/
- if (setup_tables(thd, lex->query_tables, &lex->select_lex.where,
+ if (setup_tables(thd, &thd->lex->select_lex.context,
+ lex->query_tables, &lex->select_lex.where,
&lex->select_lex.leaf_tables, FALSE))
DBUG_RETURN(TRUE);
@@ -790,7 +793,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
if (!dont_send_ok)
{
db_type table_type;
- if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN)
+ if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN)
{
my_error(ER_NO_SUCH_TABLE, MYF(0),
table_list->db, table_list->table_name);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index e1d701936cf..fc9d15e94c4 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -114,6 +114,10 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
bool is_union= first_select->next_select() &&
first_select->next_select()->linkage == UNION_TYPE;
+ /* prevent name resolving out of derived table */
+ for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
+ sl->context.outer_context= 0;
+
if (!(derived_result= new select_union(0)))
DBUG_RETURN(1); // out of memory
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index e37f3e86dda..08388dee516 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -24,7 +24,7 @@ bool mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd, 0, 0, values, 0, 0, 0))
+ if (setup_fields(thd, 0, values, 0, 0, 0))
DBUG_RETURN(TRUE);
while ((value = li++))
value->val_int();
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 8a12339ccee..2e262569386 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -146,6 +146,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
{
DBUG_RETURN(NULL);
}
+ query_cache_abort(&thd->net);
+
if (thd->warn_list.elements < thd->variables.max_error_count)
{
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 9356ee04c45..e109600bcd0 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -353,7 +353,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
LINT_INIT(key);
LINT_INIT(key_len);
- list.push_front(new Item_field(NULL,NULL,"*"));
+ thd->lex->select_lex.context.resolve_in_table_list_only(tables);
+ list.push_front(new Item_field(&thd->lex->select_lex.context,
+ NULL, NULL, "*"));
List_iterator<Item> it(list);
it++;
@@ -410,7 +412,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
tables->table=table;
if (cond && ((!cond->fixed &&
- cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
+ cond->fix_fields(thd, &cond)) || cond->check_cols(1)))
goto err0;
if (keyname)
@@ -422,7 +424,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
}
- if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0))
+ if (insert_fields(thd, &thd->lex->select_lex.context,
+ tables->db, tables->alias, &it, 0))
goto err0;
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
@@ -505,7 +508,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
{
// 'item' can be changed by fix_fields() call
if ((!item->fixed &&
- item->fix_fields(thd, tables, it_ke.ref())) ||
+ item->fix_fields(thd, it_ke.ref())) ||
(item= *it_ke.ref())->check_cols(1))
goto err;
if (item->used_tables() & ~RAND_TABLE_BIT)
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 0cf8d1e93a7..6780beec258 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -81,14 +81,18 @@ enum enum_used_fields
static bool init_fields(THD *thd, TABLE_LIST *tables,
struct st_find_field *find_fields, uint count)
{
+ Name_resolution_context *context= &thd->lex->select_lex.context;
DBUG_ENTER("init_fields");
+ context->resolve_in_table_list_only(tables);
for (; count-- ; find_fields++)
{
/* We have to use 'new' here as field will be re_linked on free */
- Item_field *field= new Item_field("mysql", find_fields->table_name,
+ 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,
- 0, REPORT_ALL_ERRORS, 1)))
+ 0, REPORT_ALL_ERRORS, 1,
+ TRUE)))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -544,7 +548,6 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
prepare_simple_select()
thd Thread handler
cond WHERE part of select
- tables list of tables, used in WHERE
table goal table
error code of error (out)
@@ -553,11 +556,11 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
# created SQL_SELECT
*/
-SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables,
+SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
TABLE *table, int *error)
{
if (!cond->fixed)
- cond->fix_fields(thd, tables, &cond); // can never fail
+ cond->fix_fields(thd, &cond); // can never fail
/* Assume that no indexes cover all required fields */
table->used_keys.clear_all();
@@ -599,7 +602,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen,
new Item_string("\\",1,&my_charset_latin1));
if (thd->is_fatal_error)
return 0; // OOM
- return prepare_simple_select(thd,cond,tables,table,error);
+ return prepare_simple_select(thd, cond, table, error);
}
@@ -651,7 +654,8 @@ bool mysqld_help(THD *thd, const char *mask)
tables do not contain VIEWs => we can pass 0 as conds
*/
- setup_tables(thd, tables, 0, &leaves, FALSE);
+ setup_tables(thd, &thd->lex->select_lex.context,
+ 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;
@@ -718,15 +722,15 @@ bool mysqld_help(THD *thd, const char *mask)
Item *cond_cat_by_cat=
new Item_func_equal(new Item_field(cat_cat_id),
new Item_int((int32)category_id));
- if (!(select= prepare_simple_select(thd,cond_topic_by_cat,
- tables,tables[0].table,&error)))
+ if (!(select= prepare_simple_select(thd, cond_topic_by_cat,
+ tables[0].table, &error)))
goto error;
get_all_items_for_category(thd,tables[0].table,
used_fields[help_topic_name].field,
select,&topics_list);
delete select;
- if (!(select= prepare_simple_select(thd,cond_cat_by_cat,tables,
- tables[1].table,&error)))
+ if (!(select= prepare_simple_select(thd, cond_cat_by_cat,
+ tables[1].table, &error)))
goto error;
get_all_items_for_category(thd,tables[1].table,
used_fields[help_category_name].field,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 5ca75554c6f..125390e4411 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd);
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table);
#endif
-static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id);
+static bool check_view_insertability(THD *thd, TABLE_LIST *view);
/* Define to force use of my_malloc() if the allocated memory block is big */
@@ -106,7 +106,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
else
{ // Part field list
- TABLE_LIST *save_next;
+ 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;
int res;
if (fields.elements != values.elements)
{
@@ -115,12 +119,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
thd->dupp_field=0;
- thd->lex->select_lex.no_wrap_view_item= 1;
- save_next= table_list->next_local; // fields only from first table
+ thd->lex->select_lex.no_wrap_view_item= TRUE;
+ /* fields only from first table */
table_list->next_local= 0;
- res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
+ context->resolve_in_table_list_only(table_list);
+ res= setup_fields(thd, 0, fields, 1, 0, 0);
table_list->next_local= save_next;
- thd->lex->select_lex.no_wrap_view_item= 0;
+ 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)
@@ -159,7 +166,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (check_key_in_view(thd, table_list) ||
(table_list->view &&
- check_view_insertability(table_list, thd->query_id)))
+ check_view_insertability(thd, table_list)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
@@ -192,7 +199,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List<Item> &update_fields)
{
TABLE *table= insert_table_list->table;
- ulong timestamp_query_id;
+ query_id_t timestamp_query_id;
LINT_INIT(timestamp_query_id);
/*
@@ -209,7 +216,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
Check the fields we are going to modify. This will set the query_id
of all used fields to the threads query_id.
*/
- if (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0))
+ if (setup_fields(thd, 0, update_fields, 1, 0, 0))
return -1;
if (table->timestamp_field)
@@ -247,6 +254,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
ulonglong id;
COPY_INFO info;
TABLE *table= 0;
+ TABLE_LIST *next_local;
List_iterator_fast<List_item> its(values_list);
List_item *values;
#ifndef EMBEDDED_LIBRARY
@@ -327,7 +335,9 @@ 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;
- // is table which we are changing used somewhere in other parts of query
+ next_local= table_list->next_local;
+ table_list->next_local= 0;
+ thd->lex->select_lex.context.resolve_in_table_list_only(table_list);
value_count= values->elements;
while ((values= its++))
{
@@ -337,10 +347,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
- if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, *values, 0, 0, 0))
goto abort;
}
its.rewind ();
+ table_list->next_local= next_local;
/*
Fill in the given fields and dump it to the table file
*/
@@ -387,12 +398,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
MODE_STRICT_ALL_TABLES)));
if ((fields.elements || !value_count) &&
- check_that_all_fields_are_given_values(thd, table))
+ check_that_all_fields_are_given_values(thd, table, table_list))
{
/* thd->net.report_error is now set, which will abort the next loop */
error= 1;
}
+ if (table_list->prepare_where(thd, 0, TRUE) ||
+ table_list->prepare_check_option(thd))
+ error= 1;
+
while ((values= its++))
{
if (fields.elements || !value_count)
@@ -596,6 +611,7 @@ abort:
SYNOPSIS
check_view_insertability()
+ thd - thread handler
view - reference on VIEW
IMPLEMENTATION
@@ -612,7 +628,7 @@ abort:
TRUE - can't be used for insert
*/
-static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
+static bool check_view_insertability(THD * thd, TABLE_LIST *view)
{
uint num= view->view->select_lex.item_list.elements;
TABLE *table= view->table;
@@ -620,15 +636,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
*trans_end= trans_start + num;
Field_translator *trans;
Field **field_ptr= table->field;
- query_id_t other_query_id= query_id - 1;
+ uint used_fields_buff_size= (table->s->fields + 7) / 8;
+ uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size);
+ MY_BITMAP used_fields;
DBUG_ENTER("check_key_in_view");
+ if (!used_fields_buff)
+ DBUG_RETURN(TRUE); // EOM
+
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
+ bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0);
+ bitmap_clear_all(&used_fields);
+
view->contain_auto_increment= 0;
/* check simplicity and prepare unique test of view */
for (trans= trans_start; trans != trans_end; trans++)
{
+ if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item))
+ return TRUE;
Item_field *field;
/* simple SELECT list entry (field without expression) */
if (!(field= trans->item->filed_for_view_update()))
@@ -636,7 +662,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
if (field->field->unireg_check == Field::NEXT_NUMBER)
view->contain_auto_increment= 1;
/* prepare unique test */
- field->field->query_id= other_query_id;
/*
remove collation (or other transparent for update function) if we have
it
@@ -648,29 +673,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
{
/* Thanks to test above, we know that all columns are of type Item_field */
Item_field *field= (Item_field *)trans->item;
- if (field->field->query_id == query_id)
+ /* check fields belong to table in which we are inserting */
+ if (field->field->table == table &&
+ bitmap_fast_test_and_set(&used_fields, field->field->field_index))
DBUG_RETURN(TRUE);
- field->field->query_id= query_id;
}
- /* VIEW contain all fields without default value */
- for (; *field_ptr; field_ptr++)
- {
- Field *field= *field_ptr;
- /* field have not default value */
- if ((field->type() == FIELD_TYPE_BLOB) &&
- (table->timestamp_field != field ||
- field->unireg_check == Field::TIMESTAMP_UN_FIELD))
- {
- for (trans= trans_start; ; trans++)
- {
- if (trans == trans_end)
- DBUG_RETURN(TRUE); // Field was not part of view
- if (((Item_field *)trans->item)->field == *field_ptr)
- break; // ok
- }
- }
- }
DBUG_RETURN(FALSE);
}
@@ -698,7 +706,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert_check_table");
- if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
+ if (setup_tables(thd, &thd->lex->select_lex.context,
+ table_list, where, &thd->lex->select_lex.leaf_tables,
select_insert))
DBUG_RETURN(TRUE);
@@ -711,7 +720,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(TRUE);
}
- DBUG_RETURN(insert_view_fields(&fields, table_list));
+ DBUG_RETURN(insert_view_fields(thd, &fields, table_list));
}
DBUG_RETURN(FALSE);
@@ -725,31 +734,63 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
mysql_prepare_insert()
thd Thread handler
table_list Global/local table list
- table Table to insert into (can be NULL if table should be taken from
- table_list->table)
+ table Table to insert into (can be NULL if table should
+ be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
+ TODO (in far future)
+ In cases of:
+ INSERT INTO t1 SELECT a, sum(a) as sum1 from t2 GROUP BY a
+ ON DUPLICATE KEY ...
+ we should be able to refer to sum1 in the ON DUPLICATE KEY part
+
+ WARNING
+ You MUST set table->insert_values to 0 after calling this function
+ before releasing the table object.
+
RETURN VALUE
FALSE OK
TRUE error
*/
-bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
- List<Item> &fields, List_item *values,
+bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
+ TABLE *table, List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic,
COND **where, bool select_insert)
{
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
+ TABLE_LIST *save_table_list;
+ TABLE_LIST *save_next_local;
bool insert_into_view= (table_list->view != 0);
- /* TODO: use this condition for 'WITH CHECK OPTION' */
- bool res;
- TABLE_LIST *next_local;
+ 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",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
+ /*
+ For subqueries in VALUES() we should not see the table in which we are
+ inserting (for INSERT ... SELECT this is done by changing table_list,
+ because INSERT ... SELECT share SELECT_LEX it with SELECT.
+ */
+ if (!select_insert)
+ {
+ for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit();
+ un;
+ un= un->next_unit())
+ {
+ for (SELECT_LEX *sl= un->first_select();
+ sl;
+ sl= sl->next_select())
+ {
+ sl->context.outer_context= 0;
+ }
+ }
+ }
+
if (duplic == DUP_UPDATE)
{
/* it should be allocated before Item::fix_fields() */
@@ -761,31 +802,54 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
select_insert))
DBUG_RETURN(TRUE);
- next_local= table_list->next_local;
+ 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;
+
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, table_list, *values, 0, 0, 0)) ||
- (duplic == DUP_UPDATE &&
- ((thd->lex->select_lex.no_wrap_view_item= 1,
- (res= check_update_fields(thd, table_list, update_fields)),
- thd->lex->select_lex.no_wrap_view_item= 0,
- res) ||
- setup_fields(thd, 0, table_list, update_values, 1, 0, 0))))
- DBUG_RETURN(TRUE);
- table_list->next_local= next_local;
+ (values && setup_fields(thd, 0, *values, 0, 0, 0)))
+ res= TRUE;
+ else if (duplic == DUP_UPDATE)
+ {
+ select_lex->no_wrap_view_item= TRUE;
+ res= check_update_fields(thd, table_list, update_fields);
+ select_lex->no_wrap_view_item= FALSE;
+ 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;
+ }
+ if (!res)
+ res= setup_fields(thd, 0, update_values, 1, 0, 0);
+ }
+ 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;
+ if (res)
+ DBUG_RETURN(res);
if (!table)
table= table_list->table;
- if (!select_insert && unique_table(table_list, table_list->next_global))
+ if (!select_insert)
{
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
- DBUG_RETURN(TRUE);
+ Item *fake_conds= 0;
+ if (unique_table(table_list, table_list->next_global))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ select_lex->fix_prepare_information(thd, &fake_conds);
+ select_lex->first_execution= 0;
}
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
- thd->lex->select_lex.first_execution= 0;
DBUG_RETURN(FALSE);
}
@@ -1038,7 +1102,8 @@ before_trg_err:
Check that all fields with arn't null_fields are used
******************************************************************************/
-int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
+int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
+ TABLE_LIST *table_list)
{
int err= 0;
for (Field **field=entry->field ; *field ; field++)
@@ -1047,10 +1112,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
((*field)->flags & NO_DEFAULT_VALUE_FLAG) &&
((*field)->real_type() != FIELD_TYPE_ENUM))
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_NO_DEFAULT_FOR_FIELD,
- ER(ER_NO_DEFAULT_FOR_FIELD),
- (*field)->field_name);
+ bool view= FALSE;
+ if (table_list)
+ {
+ table_list= (table_list->belong_to_view ?
+ table_list->belong_to_view :
+ table_list);
+ view= test(table_list->view);
+ }
+ if (view)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_DEFAULT_FOR_VIEW_FIELD,
+ ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
+ table_list->view_db.str,
+ table_list->view_name.str);
+ }
+ else
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_DEFAULT_FOR_FIELD,
+ ER(ER_NO_DEFAULT_FOR_FIELD),
+ (*field)->field_name);
+ }
err= 1;
}
}
@@ -1646,7 +1730,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
#endif
if (thd->killed || di->status)
break;
- if (error == ETIME || error == ETIMEDOUT)
+ if (error == ETIMEDOUT)
{
thd->killed= THD::KILL_CONNECTION;
break;
@@ -1932,35 +2016,37 @@ bool delayed_insert::handle_inserts(void)
bool mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
TABLE_LIST *first_select_leaf_table;
DBUG_ENTER("mysql_insert_select_prepare");
+
/*
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
clause if table is VIEW
*/
- lex->query_tables->no_where_clause= 1;
+
if (mysql_prepare_insert(thd, lex->query_tables,
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates,
- &lex->select_lex.where, TRUE))
+ &select_lex->where, TRUE))
DBUG_RETURN(TRUE);
/*
exclude first table from leaf tables list, because it belong to
INSERT
*/
- DBUG_ASSERT(lex->select_lex.leaf_tables != 0);
- lex->leaf_tables_insert= lex->select_lex.leaf_tables;
+ DBUG_ASSERT(select_lex->leaf_tables != 0);
+ lex->leaf_tables_insert= select_lex->leaf_tables;
/* skip all leaf tables belonged to view where we are insert */
- for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf;
+ for (first_select_leaf_table= select_lex->leaf_tables->next_leaf;
first_select_leaf_table &&
first_select_leaf_table->belong_to_view &&
first_select_leaf_table->belong_to_view ==
lex->leaf_tables_insert->belong_to_view;
first_select_leaf_table= first_select_leaf_table->next_leaf)
{}
- lex->select_lex.leaf_tables= first_select_leaf_table;
+ select_lex->leaf_tables= first_select_leaf_table;
DBUG_RETURN(FALSE);
}
@@ -1988,10 +2074,22 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
int
select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
+ LEX *lex= thd->lex;
+ int res;
+ SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
unit= u;
- if (check_insert_fields(thd, table_list, *fields, values, !insert_into_view))
+ /*
+ Since table in which we are going to insert is added to the first
+ select, LEX::current_select should point to the first select while
+ we are fixing fields from insert list.
+ */
+ lex->current_select= &lex->select_lex;
+ res= check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view);
+ lex->current_select= lex_current_select_save;
+ if (res)
DBUG_RETURN(1);
/*
if it is INSERT into join view then check_insert_fields already found
@@ -2003,12 +2101,12 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
Is table which we are changing used somewhere in other parts of
query
*/
- if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) &&
+ if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
unique_table(table_list, table_list->next_global))
{
/* Using same table for INSERT and SELECT */
- thd->lex->current_select->options|= OPTION_BUFFER_RESULT;
- thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
+ lex->current_select->options|= OPTION_BUFFER_RESULT;
+ lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
}
else
{
@@ -2031,8 +2129,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- DBUG_RETURN(fields->elements &&
- check_that_all_fields_are_given_values(thd, table));
+ res= ((fields->elements &&
+ check_that_all_fields_are_given_values(thd, table, table_list)) ||
+ table_list->prepare_where(thd, 0, TRUE) ||
+ table_list->prepare_check_option(thd));
+ DBUG_RETURN(res);
}
@@ -2107,9 +2208,12 @@ bool select_insert::send_data(List<Item> &values)
}
if (!(error= write_record(thd, table, &info)))
{
- if (table->triggers)
+ if (table->triggers || info.handle_duplicates == DUP_UPDATE)
{
/*
+ Restore fields of the record since it is possible that they were
+ changed by ON DUPLICATE KEY UPDATE clause.
+
If triggers exist then whey can modify some fields which were not
originally touched by INSERT ... SELECT, so we have to restore
their original values for the next row.
@@ -2275,7 +2379,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- DBUG_RETURN(check_that_all_fields_are_given_values(thd, table));
+ DBUG_RETURN(check_that_all_fields_are_given_values(thd, table,
+ table_list));
}
@@ -2362,11 +2467,11 @@ void select_create::abort()
Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator_fast<List_item>;
#ifndef EMBEDDED_LIBRARY
template class I_List<delayed_insert>;
template class I_List_iterator<delayed_insert>;
template class I_List<delayed_row>;
#endif /* EMBEDDED_LIBRARY */
-#endif /* __GNUC__ */
+#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 8657b738b28..630a7e950f7 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -145,7 +145,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->found_semicolon= 0;
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
- lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0;
+ 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;
@@ -164,7 +164,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->current_select= &lex->select_lex;
lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
- lex->sql_command=SQLCOM_END;
+ lex->sql_command= lex->orig_sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->sphead= NULL;
@@ -172,10 +172,9 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->proc_list.first= 0;
lex->query_tables_own_last= 0;
- if (lex->spfuns.records)
- my_hash_reset(&lex->spfuns);
- if (lex->spprocs.records)
- my_hash_reset(&lex->spprocs);
+ if (lex->sroutines.records)
+ my_hash_reset(&lex->sroutines);
+ lex->sroutines_list.empty();
DBUG_VOID_RETURN;
}
@@ -557,6 +556,15 @@ int yylex(void *arg, void *yythd)
lex->next_state= MY_LEX_START; // Allow signed numbers
if (c == ',')
lex->tok_start=lex->ptr; // Let tok_start point at next item
+ /*
+ Check for a placeholder: it should not precede a possible identifier
+ because of binlogging: when a placeholder is replaced with
+ its value in a query for the binlog, the query must stay
+ grammatically correct.
+ */
+ else if (c == '?' && ((THD*) yythd)->command == COM_STMT_PREPARE &&
+ !ident_map[cs, yyPeek()])
+ return(PARAM_MARKER);
return((int) c);
case MY_LEX_IDENT_OR_NCHAR:
@@ -967,7 +975,7 @@ int yylex(void *arg, void *yythd)
{
THD* thd= (THD*)yythd;
if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
- (thd->command != COM_PREPARE))
+ (thd->command != COM_STMT_PREPARE))
{
lex->safe_to_cache_query= 0;
lex->found_semicolon=(char*) lex->ptr;
@@ -1104,7 +1112,8 @@ void st_select_lex::init_query()
having= where= prep_where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
- resolve_mode= NOMATTER_MODE;
+ context.select_lex= this;
+ context.init();
cond_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
@@ -1571,6 +1580,28 @@ void st_select_lex::print_limit(THD *thd, String *str)
/*
+ Initialize LEX object.
+
+ SYNOPSIS
+ st_lex::st_lex()
+
+ NOTE
+ LEX object initialized with this constructor can be used as part of
+ THD object for which one can safely call open_tables(), lock_tables()
+ and close_thread_tables() functions. But it is not yet ready for
+ statement parsing. On should use lex_start() function to prepare LEX
+ for this.
+*/
+
+st_lex::st_lex()
+ :result(0), sql_command(SQLCOM_END), query_tables_own_last(0)
+{
+ hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
+ sroutines_list.empty();
+}
+
+
+/*
Check whether the merging algorithm can be used on this VIEW
SYNOPSIS
@@ -1703,8 +1734,7 @@ bool st_lex::can_not_use_merged()
bool st_lex::only_view_structure()
{
- switch(sql_command)
- {
+ switch (sql_command) {
case SQLCOM_SHOW_CREATE:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_FIELDS:
@@ -1744,6 +1774,31 @@ bool st_lex::need_correct_ident()
}
}
+/*
+ Get effective type of CHECK OPTION for given view
+
+ SYNOPSIS
+ get_effective_with_check()
+ view given view
+
+ NOTE
+ It have not sense to set CHECK OPTION for SELECT satement or subqueries,
+ so we do not.
+
+ RETURN
+ VIEW_CHECK_NONE no need CHECK OPTION
+ VIEW_CHECK_LOCAL CHECK OPTION LOCAL
+ VIEW_CHECK_CASCADED CHECK OPTION CASCADED
+*/
+
+uint8 st_lex::get_effective_with_check(st_table_list *view)
+{
+ if (view->select_lex->master_unit() == &unit &&
+ which_check_option_applicable())
+ return (uint8)view->with_check;
+ return VIEW_CHECK_NONE;
+}
+
/*
initialize limit counters
@@ -1755,12 +1810,13 @@ bool st_lex::need_correct_ident()
void st_select_lex_unit::set_limit(SELECT_LEX *sl)
{
- ulonglong select_limit_val;
+ ha_rows select_limit_val;
DBUG_ASSERT(! thd->current_arena->is_stmt_prepare());
- select_limit_val= sl->select_limit ? sl->select_limit->val_uint() :
- HA_POS_ERROR;
- offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
+ select_limit_val= (ha_rows)(sl->select_limit ? sl->select_limit->val_uint() :
+ HA_POS_ERROR);
+ offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() :
+ ULL(0));
select_limit_cnt= select_limit_val + offset_limit_cnt;
if (select_limit_cnt < select_limit_val)
select_limit_cnt= HA_POS_ERROR; // no limit
@@ -1804,7 +1860,8 @@ 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*) first->next_local;
+ select_lex.table_list.first= (byte*) (select_lex.context.table_list=
+ first->next_local);
select_lex.table_list.elements--; //safety
first->next_local= 0;
/*
@@ -1909,13 +1966,51 @@ 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*) first;
+ select_lex.table_list.first=
+ (byte*) (select_lex.context.table_list= first);
select_lex.table_list.elements++; //safety
}
}
}
+
+/*
+ cleanup lex for case when we open table by table for processing
+
+ SYNOPSIS
+ st_lex::cleanup_after_one_table_open()
+*/
+
+void st_lex::cleanup_after_one_table_open()
+{
+ /*
+ thd->lex->derived_tables & additional units may be set if we open
+ a view. It is necessary to clear thd->lex->derived_tables flag
+ to prevent processing of derived tables during next open_and_lock_tables
+ if next table is a real table and cleanup & remove underlying units
+ NOTE: all units will be connected to thd->lex->select_lex, because we
+ have not UNION on most upper level.
+ */
+ if (all_selects_list != &select_lex)
+ {
+ derived_tables= 0;
+ /* cleunup underlying units (units of VIEW) */
+ for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit();
+ un;
+ un= un->next_unit())
+ un->cleanup();
+ /* reduce all selects list to default state */
+ all_selects_list= &select_lex;
+ /* remove underlying units (units of VIEW) subtree */
+ select_lex.cut_subtree();
+ }
+ time_zone_tables_used= 0;
+ if (sroutines.records)
+ my_hash_reset(&sroutines);
+}
+
+
/*
fix some structures at the end of preparation
@@ -1930,7 +2025,21 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
if (!thd->current_arena->is_conventional() && first_execution)
{
first_execution= 0;
- prep_where= where;
+ if (*conds)
+ {
+ prep_where= *conds;
+ *conds= where= prep_where->copy_andor_structure(thd);
+ }
+ for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first;
+ tbl;
+ tbl= tbl->next_local)
+ {
+ if (tbl->on_expr)
+ {
+ tbl->prep_on_expr= tbl->on_expr;
+ tbl->on_expr= tbl->on_expr->copy_andor_structure(thd);
+ }
+ }
}
}
@@ -1945,3 +2054,4 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
st_select_lex_unit::change_result
are in sql_union.cc
*/
+
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 052873640c6..45c8182a29c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -304,7 +304,7 @@ protected:
*link_next, **link_prev; /* list of whole SELECT_LEX */
public:
- ulonglong options;
+ ulong options;
/*
result of this query can't be cached, bit field, can be :
UNCACHEABLE_DEPENDENT
@@ -371,7 +371,6 @@ typedef class st_select_lex_node SELECT_LEX_NODE;
SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group
SELECT_LEXs
*/
-struct st_lex;
class THD;
class select_result;
class JOIN;
@@ -470,6 +469,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT;
class st_select_lex: public st_select_lex_node
{
public:
+ Name_resolution_context context;
char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
Item *where, *having; /* WHERE & HAVING clauses */
Item *prep_where; /* saved WHERE clause for prepared statement processing */
@@ -530,34 +530,25 @@ public:
query processing end even if we use temporary table
*/
bool subquery_in_having;
- bool first_execution; /* first execution in SP or PS */
+ /*
+ This variable is required to ensure proper work of subqueries and
+ stored procedures. Generally, one should use the states of
+ Query_arena to determine if it's a statement prepare or first
+ execution of a stored procedure. However, in case when there was an
+ error during the first execution of a stored procedure, the SP body
+ is not expelled from the SP cache. Therefore, a deeply nested
+ subquery might be left unoptimized. So we need this per-subquery
+ variable to inidicate the optimization/execution state of every
+ subquery. Prepared statements work OK in that regard, as in
+ case of an error during prepare the PS is not created.
+ */
+ bool first_execution;
bool first_cond_optimization;
/* do not wrap view fields with Item_ref */
bool no_wrap_view_item;
/* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test;
- /*
- SELECT for SELECT command st_select_lex. Used to privent scaning
- item_list of non-SELECT st_select_lex (no sense find to finding
- reference in it (all should be in tables, it is dangerouse due
- to order of fix_fields calling for non-SELECTs commands (item list
- can be not fix_fieldsd)). This value will be assigned for
- primary select (sql_yac.yy) and for any subquery and
- UNION SELECT (sql_parse.cc mysql_new_select())
-
-
- INSERT for primary st_select_lex structure of simple INSERT/REPLACE
- (used for name resolution, see Item_fiels & Item_ref fix_fields,
- FALSE for INSERT/REPLACE ... SELECT, because it's
- st_select_lex->table_list will be preprocessed (first table removed)
- before passing to handle_select)
-
- NOMATTER for other
- */
- enum {NOMATTER_MODE, SELECT_MODE, INSERT_MODE} resolve_mode;
-
-
void init_query();
void init_select();
st_select_lex_unit* master_unit();
@@ -615,7 +606,13 @@ public:
order_list.first= 0;
order_list.next= (byte**) &order_list.first;
}
-
+ /*
+ This method created for reiniting LEX in mysql_admin_table() and can be
+ used only if you are going remove all SELECT_LEX & units except belonger
+ to LEX (LEX::unit & LEX::select, for other purposes there are
+ SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree
+ */
+ void cut_subtree() { slave= 0; }
bool test_limit();
friend void lex_start(THD *thd, uchar *buf, uint length);
@@ -630,6 +627,11 @@ public:
static void print_order(String *str, ORDER *order);
void print_limit(THD *thd, String *str);
void fix_prepare_information(THD *thd, Item **conds);
+ /*
+ Destroy the used execution plan (JOIN) of this subtree (this
+ SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs).
+ */
+ bool cleanup();
};
typedef class st_select_lex SELECT_LEX;
@@ -717,7 +719,6 @@ typedef struct st_lex
function)
*/
TABLE_LIST **query_tables_last;
- TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
@@ -805,8 +806,14 @@ typedef struct st_lex
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
bool all_privileges;
sp_pcontext *spcont;
- HASH spfuns; /* Called functions */
- HASH spprocs; /* Called procedures */
+ /* Set of stored routines called by statement. */
+ HASH sroutines;
+ /*
+ List linking elements of 'sroutines' set. Allows you to add new elements
+ to this set as you iterate through the list of existing elements.
+ */
+ SQL_LIST sroutines_list;
+
st_sp_chistics sp_chistics;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
@@ -839,17 +846,11 @@ typedef struct st_lex
*/
uchar *fname_start, *fname_end;
- st_lex() :result(0), sql_command(SQLCOM_END), query_tables_own_last(0)
- {
- extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
- hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
- hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
- }
+ st_lex();
virtual ~st_lex()
{
- hash_free(&spfuns);
- hash_free(&spprocs);
+ hash_free(&sroutines);
}
inline void uncacheable(uint8 cause)
@@ -886,7 +887,30 @@ typedef struct st_lex
bool can_not_use_merged();
bool only_view_structure();
bool need_correct_ident();
+ uint8 get_effective_with_check(st_table_list *view);
+ /*
+ Is this update command where 'WHITH CHECK OPTION' clause is important
+ SYNOPSIS
+ st_lex::which_check_option_applicable()
+
+ RETURN
+ TRUE have to take 'WHITH CHECK OPTION' clause into account
+ FALSE 'WHITH CHECK OPTION' clause do not need
+ */
+ inline bool which_check_option_applicable()
+ {
+ switch (sql_command) {
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ case SQLCOM_INSERT:
+ case SQLCOM_INSERT_SELECT:
+ case SQLCOM_LOAD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
inline bool requires_prelocking()
{
return test(query_tables_own_last);
@@ -900,7 +924,7 @@ typedef struct st_lex
{
return ( query_tables_own_last ? *query_tables_own_last : 0);
}
-
+ void cleanup_after_one_table_open();
} LEX;
struct st_lex_local: public st_lex
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index cc25839bcc9..1ec209aba85 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -149,7 +149,8 @@ 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, table_list, &unused_conds,
+ if (setup_tables(thd, &thd->lex->select_lex.context,
+ table_list, &unused_conds,
&thd->lex->select_lex.leaf_tables, FALSE))
DBUG_RETURN(-1);
if (!table_list->table || // do not suport join view
@@ -159,6 +160,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD");
DBUG_RETURN(TRUE);
}
+ if (table_list->prepare_where(thd, 0, TRUE) ||
+ table_list->prepare_check_option(thd))
+ {
+ DBUG_RETURN(TRUE);
+ }
/*
Let us emit an error if we are loading data to table which is used
in subselect in SET clause like we do it for INSERT.
@@ -186,16 +192,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
Let us also prepare SET clause, altough it is probably empty
in this case.
*/
- if (setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) ||
- setup_fields(thd, 0, table_list, set_values, 1, 0, 0))
+ if (setup_fields(thd, 0, set_fields, 1, 0, 0) ||
+ setup_fields(thd, 0, set_values, 1, 0, 0))
DBUG_RETURN(TRUE);
}
else
{ // Part field list
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
- if (setup_fields(thd, 0, table_list, fields_vars, 1, 0, 0) ||
- setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) ||
- check_that_all_fields_are_given_values(thd, table))
+ if (setup_fields(thd, 0, fields_vars, 1, 0, 0) ||
+ setup_fields(thd, 0, set_fields, 1, 0, 0) ||
+ check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/*
Check whenever TIMESTAMP field with auto-set feature specified
@@ -209,7 +215,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
check_that_all_fields_are_given_values() and setting use_timestamp
since it may update query_id for some fields.
*/
- if (setup_fields(thd, 0, table_list, set_values, 1, 0, 0))
+ if (setup_fields(thd, 0, set_values, 1, 0, 0))
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 9346f3df305..56b4b765355 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -138,7 +138,7 @@ void unmap_file(mapped_files *map)
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/* Used templates */
template class I_List<mapped_files>;
template class I_List_iterator<mapped_files>;
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 831b15cf7ef..71e8fe4149f 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -77,7 +77,8 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new
{
not_found= 0;
((Item_field*)new_item)->db_name=iif->db_name;
- Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name);
+ Item_field *new_one=new Item_field(&select_lex->context,
+ iif->db_name, iif->table_name, iif->field_name);
privlist.push_back(new_one);
if (add_to_list(new_select->group_list,new_one,1))
return 1;
@@ -152,12 +153,11 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
List<Item> all_fields(select_lex->item_list);
- if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first
+ if (setup_tables(lex->thd, &select_lex->context,
+ (TABLE_LIST *)select_lex->table_list.first
&select_lex->where, &select_lex->leaf_tables, FALSE) ||
- setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
- select_lex->item_list, 1, &all_fields,1) ||
- setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
- item_list_copy, 1, &all_fields, 1))
+ setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) ||
+ setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1))
return -1;
if (select_lex->olap == CUBE_TYPE)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 91bccd4dd11..2e5cab4bb1c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1634,32 +1634,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
break;
}
- case COM_EXECUTE:
+ case COM_STMT_EXECUTE:
{
mysql_stmt_execute(thd, packet, packet_length);
break;
}
- case COM_FETCH:
+ case COM_STMT_FETCH:
{
mysql_stmt_fetch(thd, packet, packet_length);
break;
}
- case COM_LONG_DATA:
+ case COM_STMT_SEND_LONG_DATA:
{
mysql_stmt_get_longdata(thd, packet, packet_length);
break;
}
- case COM_PREPARE:
+ case COM_STMT_PREPARE:
{
mysql_stmt_prepare(thd, packet, packet_length, 0);
break;
}
- case COM_CLOSE_STMT:
+ case COM_STMT_CLOSE:
{
- mysql_stmt_free(thd, packet);
+ mysql_stmt_close(thd, packet);
break;
}
- case COM_RESET_STMT:
+ case COM_STMT_RESET:
{
mysql_stmt_reset(thd, packet);
break;
@@ -2193,13 +2193,15 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
table_list->schema_select_lex= sel;
table_list->schema_table_reformed= 1;
+ statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
+ &LOCK_status);
DBUG_RETURN(0);
}
/*
Read query from packet and store in thd->query
- Used in COM_QUERY and COM_PREPARE
+ Used in COM_QUERY and COM_STMT_PREPARE
DESCRIPTION
Sets the following THD variables:
@@ -2289,6 +2291,10 @@ mysql_execute_command(THD *thd)
lex->first_lists_tables_same();
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
+ /* set context for commands which do not use setup_tables */
+ select_lex->
+ context.resolve_in_table_list_only((TABLE_LIST*)select_lex->
+ table_list.first);
/*
Reset warning count for each query that uses tables
@@ -2298,8 +2304,7 @@ mysql_execute_command(THD *thd)
Don't reset warnings when executing a stored routine.
*/
if ((all_tables || &lex->select_lex != lex->all_selects_list ||
- lex->spfuns.records || lex->spprocs.records) &&
- !thd->spcont)
+ lex->sroutines.records) && !thd->spcont)
mysql_reset_errors(thd, 0);
#ifdef HAVE_REPLICATION
@@ -2351,10 +2356,6 @@ mysql_execute_command(THD *thd)
}
#endif /* !HAVE_REPLICATION */
-
-
-
-
/*
When option readonly is set deny operations which change tables.
Except for the replication thread and the 'super' users.
@@ -2366,9 +2367,10 @@ mysql_execute_command(THD *thd)
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(-1);
}
+ if(lex->orig_sql_command == SQLCOM_END)
+ statistic_increment(thd->status_var.com_stat[lex->sql_command],
+ &LOCK_status);
- statistic_increment(thd->status_var.com_stat[lex->sql_command],
- &LOCK_status);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -2501,7 +2503,7 @@ mysql_execute_command(THD *thd)
lex->prepared_stmt_name.str,
query_len, query_str));
}
- thd->command= COM_PREPARE;
+ thd->command= COM_STMT_PREPARE;
if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1,
&lex->prepared_stmt_name)))
send_ok(thd, 0L, 0L, "Statement prepared");
@@ -2572,7 +2574,7 @@ mysql_execute_command(THD *thd)
goto error;
/* PURGE MASTER LOGS BEFORE 'data' */
it= (Item *)lex->value_list.head();
- if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) ||
+ if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
it->check_cols(1))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
@@ -2881,9 +2883,7 @@ mysql_execute_command(THD *thd)
CREATE from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
*/
- select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
res= handle_select(thd, lex, result, 0);
- select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
delete result;
}
/* reset for PS */
@@ -3222,6 +3222,8 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
+ /* Skip first table, which is the table we are inserting in */
+ select_lex->context.table_list= first_table->next_local;
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
@@ -3232,6 +3234,7 @@ end_with_restore_list:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
+ select_result *result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
@@ -3243,27 +3246,24 @@ end_with_restore_list:
/* Don't unlock tables until command is written to binary log */
select_lex->options|= SELECT_NO_UNLOCK;
- select_result *result;
unit->set_limit(select_lex);
-
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;
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->update_list,
+ &lex->value_list,
lex->duplicates, lex->ignore)))
{
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
+ /* Skip first table, which is the table we are inserting in */
+ select_lex->context.table_list= first_table->next_local;
+
res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
- select_lex->resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
}
/* revert changes for SP */
@@ -3272,7 +3272,6 @@ end_with_restore_list:
if (first_table->view && !first_table->contain_auto_increment)
thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
-
break;
}
case SQLCOM_TRUNCATE:
@@ -3864,7 +3863,7 @@ end_with_restore_list:
{
Item *it= (Item *)lex->value_list.head();
- if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1))
+ if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
{
my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
MYF(0));
@@ -5190,7 +5189,6 @@ mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
- lex->orig_sql_command= SQLCOM_END;
lex->wild= 0;
if (select_lex == &lex->select_lex)
{
@@ -5213,6 +5211,11 @@ mysql_new_select(LEX *lex, bool move_down)
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
+ mysql_stmt_prepare.
+ */
if (thd->current_arena->is_stmt_prepare())
select_lex->uncacheable|= UNCACHEABLE_PREPARE;
if (move_down)
@@ -5231,16 +5234,27 @@ mysql_new_select(LEX *lex, bool move_down)
unit->link_prev= 0;
unit->return_to= lex->current_select;
select_lex->include_down(unit);
- /* TODO: assign resolve_mode for fake subquery after merging with new tree */
+ /*
+ By default we assume that it is usual subselect and we have outer name
+ resolution context, if no we will assign it to 0 later
+ */
+ select_lex->context.outer_context= &select_lex->outer_select()->context;
}
else
{
+ Name_resolution_context *outer_context;
if (lex->current_select->order_list.first && !lex->current_select->braces)
{
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
DBUG_RETURN(1);
}
select_lex->include_neighbour(lex->current_select);
+ /*
+ we are not sure that we have one level of SELECTs above, so we take
+ outer_context address from first select of unit
+ */
+ outer_context=
+ select_lex->master_unit()->first_select()->context.outer_context;
SELECT_LEX_UNIT *unit= select_lex->master_unit();
SELECT_LEX *fake= unit->fake_select_lex;
if (!fake)
@@ -5257,13 +5271,23 @@ mysql_new_select(LEX *lex, bool move_down)
fake->make_empty_select();
fake->linkage= GLOBAL_OPTIONS_TYPE;
fake->select_limit= 0;
+
+ fake->context.outer_context= outer_context;
+ /* allow item list resolving in fake select for ORDER BY */
+ fake->context.resolve_in_select_list= TRUE;
+ fake->context.select_lex= fake;
}
+ select_lex->context.outer_context= outer_context;
}
select_lex->master_unit()->global_parameters= select_lex;
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
- select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
+ /*
+ in subquery is SELECT query and we allow resolution of names in SELECT
+ list
+ */
+ select_lex->context.resolve_in_select_list= TRUE;
DBUG_RETURN(0);
}
@@ -5494,6 +5518,21 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
DBUG_RETURN(1);
}
+ if (type == FIELD_TYPE_TIMESTAMP && length)
+ {
+ /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
+ In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
+ and so on, the display width is ignored.
+ */
+ char buf[32];
+ my_snprintf(buf, sizeof(buf),
+ "TIMESTAMP(%s)", length, system_charset_info);
+ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER(ER_WARN_DEPRECATED_SYNTAX),
+ buf, "TIMESTAMP");
+ }
+
if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
type_modifier, default_value, on_update_value,
comment, change, interval_list, cs, uint_geom_type)))
@@ -5531,8 +5570,14 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
new_field->flags= type_modifier;
new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
Field::NEXT_NUMBER : Field::NONE);
- new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
- NOT_FIXED_DEC-1) : 0;
+ new_field->decimals= decimals ? (uint)atoi(decimals) : 0;
+ if (new_field->decimals >= NOT_FIXED_DEC)
+ {
+ my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name,
+ NOT_FIXED_DEC-1);
+ DBUG_RETURN(NULL);
+ }
+
new_field->sql_type=type;
new_field->length=0;
new_field->change=change;
@@ -5553,11 +5598,6 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
length=0; /* purecov: inspected */
sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
- if (new_field->length && new_field->decimals &&
- new_field->length < new_field->decimals+1 &&
- new_field->decimals != NOT_FIXED_DEC)
- new_field->length=new_field->decimals+1; /* purecov: inspected */
-
switch (type) {
case FIELD_TYPE_TINY:
if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
@@ -5583,22 +5623,24 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_NEWDECIMAL:
if (!length)
+ new_field->length= 10;
+ if (new_field->length > DECIMAL_MAX_PRECISION)
{
- if (!(new_field->length= new_field->decimals))
- new_field->length= 10; // Default length for DECIMAL
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name,
+ DECIMAL_MAX_PRECISION);
+ DBUG_RETURN(NULL);
}
- new_field->pack_length=
- my_decimal_get_binary_size(new_field->length, new_field->decimals);
- if (new_field->length <= DECIMAL_MAX_PRECISION &&
- new_field->length >= new_field->decimals)
+ if (new_field->length < new_field->decimals)
{
- new_field->length=
- my_decimal_precision_to_length(new_field->length, new_field->decimals,
- type_modifier & UNSIGNED_FLAG);
- break;
+ my_error(ER_SCALE_BIGGER_THAN_PRECISION, MYF(0), field_name);
+ DBUG_RETURN(NULL);
}
- my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
- DBUG_RETURN(NULL);
+ new_field->length=
+ my_decimal_precision_to_length(new_field->length, new_field->decimals,
+ type_modifier & UNSIGNED_FLAG);
+ new_field->pack_length=
+ my_decimal_get_binary_size(new_field->length, new_field->decimals);
+ break;
case MYSQL_TYPE_VARCHAR:
/*
Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
@@ -6367,9 +6409,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
*/
/*
- Writing this command to the binlog may result in infinite loops when doing
- mysqlbinlog|mysql, and anyway it does not really make sense to log it
- automatically (would cause more trouble to users than it would help them)
+ Writing this command to the binlog may result in infinite loops
+ when doing mysqlbinlog|mysql, and anyway it does not really make
+ sense to log it automatically (would cause more trouble to users
+ than it would help them)
*/
tmp_write_to_binlog= 0;
mysql_log.new_file(1);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index e0a19e2f09e..3e291243e1e 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -19,9 +19,9 @@ This file contains the implementation of prepare and executes.
Prepare:
- - Server gets the query from client with command 'COM_PREPARE';
+ - Server gets the query from client with command 'COM_STMT_PREPARE';
in the following format:
- [COM_PREPARE:1] [query]
+ [COM_STMT_PREPARE:1] [query]
- Parse the query and recognize any parameter markers '?' and
store its information list in lex->param_list
- Allocate a new statement for this prepare; and keep this in
@@ -37,10 +37,10 @@ Prepare:
Prepare-execute:
- - Server gets the command 'COM_EXECUTE' to execute the
+ - Server gets the command 'COM_STMT_EXECUTE' to execute the
previously prepared query. If there is any param markers; then client
will send the data in the following format:
- [COM_EXECUTE:1]
+ [COM_STMT_EXECUTE:1]
[STMT_ID:4]
[NULL_BITS:(param_count+7)/8)]
[TYPES_SUPPLIED_BY_CLIENT(0/1):1]
@@ -55,9 +55,10 @@ Prepare-execute:
Long data handling:
- - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
+ - Server gets the long data in pieces with command type
+ 'COM_STMT_SEND_LONG_DATA'.
- The packet recieved will have the format as:
- [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
+ [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
- data from the packet is appended to long data value buffer for this
placeholder.
- It's up to the client to check for read data ended. The server doesn't
@@ -105,6 +106,7 @@ public:
virtual ~Prepared_statement();
void setup_set_params();
virtual Query_arena::Type type() const;
+ virtual void close_cursor();
};
static void execute_stmt(THD *thd, Prepared_statement *stmt,
@@ -311,24 +313,28 @@ static void set_param_int64(Item_param *param, uchar **pos, ulong len)
static void set_param_float(Item_param *param, uchar **pos, ulong len)
{
+ float data;
#ifndef EMBEDDED_LIBRARY
if (len < 4)
return;
-#endif
- float data;
float4get(data,*pos);
+#else
+ data= *(float*) *pos;
+#endif
param->set_double((double) data);
*pos+= 4;
}
static void set_param_double(Item_param *param, uchar **pos, ulong len)
{
+ double data;
#ifndef EMBEDDED_LIBRARY
if (len < 8)
return;
-#endif
- double data;
float8get(data,*pos);
+#else
+ data= *(double*) *pos;
+#endif
param->set_double((double) data);
*pos+= 8;
}
@@ -916,12 +922,12 @@ static bool mysql_test_insert(Prepared_statement *stmt,
goto error;
/*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- Note that this is done without locks (should not be needed as we will not
- access any data here)
- 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.
+ open temporary memory pool for temporary data allocated by derived
+ tables & preparation procedure
+ Note that this is done without locks (should not be needed as we will not
+ access any data here)
+ 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))
goto error;
@@ -938,9 +944,9 @@ static bool mysql_test_insert(Prepared_statement *stmt,
table_list->table->insert_values=(byte *)1;
}
- if (mysql_prepare_insert(thd, table_list, table_list->table, fields,
- values, update_fields, update_values, duplic,
- &unused_conds, FALSE))
+ if (mysql_prepare_insert(thd, table_list, table_list->table,
+ fields, values, update_fields, update_values,
+ duplic, &unused_conds, FALSE))
goto error;
value_count= values->elements;
@@ -962,7 +968,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, *values, 0, 0, 0))
goto error;
}
}
@@ -1038,9 +1044,9 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->grant.want_privilege= want_privilege;
table_list->table->grant.want_privilege= want_privilege;
#endif
- thd->lex->select_lex.no_wrap_view_item= 1;
- res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0);
- thd->lex->select_lex.no_wrap_view_item= 0;
+ thd->lex->select_lex.no_wrap_view_item= TRUE;
+ res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
+ thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1049,7 +1055,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->table->grant.want_privilege=
(SELECT_ACL & ~table_list->table->grant.privilege);
#endif
- if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0))
+ if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
goto error;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0);
@@ -1118,6 +1124,8 @@ static bool mysql_test_select(Prepared_statement *stmt,
SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_test_select");
+ lex->select_lex.context.resolve_in_select_list= TRUE;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (tables)
@@ -1206,7 +1214,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (open_and_lock_tables(thd, tables))
DBUG_RETURN(TRUE);
- DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0));
+ DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0));
}
@@ -1276,6 +1284,8 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
+ lex->select_lex.context.resolve_in_select_list= TRUE;
+
if (specific_prepare && (*specific_prepare)(thd))
DBUG_RETURN(TRUE);
@@ -1353,9 +1363,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
if (select_lex->item_list.elements)
{
- select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
+ select_lex->context.resolve_in_select_list= TRUE;
res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
- select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
}
/* put tables back for PS rexecuting */
@@ -1445,16 +1454,21 @@ error:
static bool mysql_insert_select_prepare_tester(THD *thd)
{
+ TABLE_LIST *first;
+ bool res;
SELECT_LEX *first_select= &thd->lex->select_lex;
/* Skip first table, which is the table we are inserting in */
- first_select->table_list.first= (byte*)((TABLE_LIST*)first_select->
- table_list.first)->next_local;
+ first_select->table_list.first= (byte*)(first=
+ ((TABLE_LIST*)first_select->
+ table_list.first)->next_local);
+ res= mysql_insert_select_prepare(thd);
/*
insert/replace from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
*/
- first_select->resolve_mode= SELECT_LEX::SELECT_MODE;
- return mysql_insert_select_prepare(thd);
+ thd->lex->select_lex.context.resolve_in_select_list= TRUE;
+ thd->lex->select_lex.context.table_list= first;
+ return res;
}
@@ -1492,12 +1506,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first;
DBUG_ASSERT(first_local_table != 0);
- res= select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_insert_select_prepare_tester,
- OPTION_SETUP_TABLES_DONE);
+ res=
+ select_like_stmt_test_with_open_n_lock(stmt, tables,
+ &mysql_insert_select_prepare_tester,
+ OPTION_SETUP_TABLES_DONE);
/* revert changes made by mysql_insert_select_prepare_tester */
lex->select_lex.table_list.first= (byte*) first_local_table;
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
return res;
}
@@ -1537,6 +1551,10 @@ static bool check_prepared_statement(Prepared_statement *stmt,
lex->first_lists_tables_same();
tables= lex->query_tables;
+ /* set context for commands which do not use setup_tables */
+ lex->select_lex.context.resolve_in_table_list_only(select_lex->
+ get_table_list());
+
switch (sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
@@ -1705,6 +1723,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
LEX_STRING *name)
{
LEX *lex;
+ Statement stmt_backup;
Prepared_statement *stmt= new Prepared_statement(thd);
bool error;
DBUG_ENTER("mysql_stmt_prepare");
@@ -1738,13 +1757,13 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
DBUG_RETURN(TRUE);
}
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
+ thd->set_n_backup_item_arena(stmt, &stmt_backup);
if (alloc_query(thd, packet, packet_length))
{
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
DBUG_RETURN(TRUE);
@@ -1769,7 +1788,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
transformation can be reused on execute, we set again thd->mem_root from
stmt->mem_root (see setup_wild for one place where we do that).
*/
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
if (!error)
error= check_prepared_statement(stmt, test(name));
@@ -1785,7 +1804,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
lex_end(lex);
close_thread_tables(thd);
cleanup_stmt_and_thd_after_use(stmt, thd);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
thd->current_arena= thd;
if (error)
@@ -1812,17 +1831,11 @@ void init_stmt_after_parse(THD *thd, LEX *lex)
{
SELECT_LEX *sl= lex->all_selects_list;
/*
- Save WHERE clause pointers, because they may be changed during query
- optimisation.
+ Switch off a temporary flag that prevents evaluation of
+ subqueries in statement prepare.
*/
for (; sl; sl= sl->next_select_in_list())
- {
- sl->prep_where= sl->where;
- sl->uncacheable&= ~UNCACHEABLE_PREPARE;
- }
-
- for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
- table->prep_on_expr= table->on_expr;
+ sl->uncacheable&= ~UNCACHEABLE_PREPARE;
}
@@ -1948,6 +1961,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) ((uchar) packet[4]);
+ Statement stmt_backup;
Cursor *cursor;
/*
Query text for binary log, or empty string if the query is not put into
@@ -1977,10 +1991,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
cursor= stmt->cursor;
if (cursor && cursor->is_open())
- {
- my_error(ER_EXEC_STMT_WITH_OPEN_CURSOR, MYF(0));
- DBUG_VOID_RETURN;
- }
+ stmt->close_cursor();
DBUG_ASSERT(thd->free_list == NULL);
mysql_reset_thd_for_next_command(thd);
@@ -2001,7 +2012,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
DBUG_PRINT("info",("Using READ_ONLY cursor"));
if (!cursor &&
- !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
+ !(cursor= stmt->cursor= new (stmt->mem_root) Cursor(thd)))
DBUG_VOID_RETURN;
/* If lex->result is set, mysql_execute_command will use it */
stmt->lex->result= &cursor->result;
@@ -2025,8 +2036,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
thd->current_arena= stmt;
reinit_stmt_before_use(thd, stmt->lex);
/* From now cursors assume that thd->mem_root is clean */
@@ -2063,7 +2073,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
reset_stmt_params(stmt);
}
- thd->set_statement(&thd->stmt_backup);
+ thd->set_statement(&stmt_backup);
thd->current_arena= thd;
DBUG_VOID_RETURN;
@@ -2088,6 +2098,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
binary log.
*/
String expanded_query;
+ Statement stmt_backup;
DBUG_ENTER("mysql_sql_stmt_execute");
DBUG_ASSERT(thd->free_list == NULL);
@@ -2109,16 +2120,16 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
/* Must go before setting variables, as it clears thd->user_var_events */
mysql_reset_thd_for_next_command(thd);
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (stmt->set_params_from_vars(stmt,
- thd->stmt_backup.lex->prepared_stmt_params,
+ stmt_backup.lex->prepared_stmt_params,
&expanded_query))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
}
- thd->command= COM_EXECUTE; /* For nice messages in general log */
+ thd->command= COM_STMT_EXECUTE; /* For nice messages in general log */
execute_stmt(thd, stmt, &expanded_query);
+ thd->set_statement(&stmt_backup);
DBUG_VOID_RETURN;
}
@@ -2175,7 +2186,6 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
close_thread_tables(thd); // to close derived tables
cleanup_stmt_and_thd_after_use(stmt, thd);
reset_stmt_params(stmt);
- thd->set_statement(&thd->stmt_backup);
thd->current_arena= thd;
if (stmt->state == Query_arena::PREPARED)
@@ -2185,7 +2195,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
/*
- COM_FETCH handler: fetches requested amount of rows from cursor
+ COM_STMT_FETCH handler: fetches requested amount of rows from cursor
SYNOPSIS
mysql_stmt_fetch()
@@ -2200,41 +2210,49 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
ulong stmt_id= uint4korr(packet);
ulong num_rows= uint4korr(packet+4);
Prepared_statement *stmt;
+ Statement stmt_backup;
+ Cursor *cursor;
DBUG_ENTER("mysql_stmt_fetch");
statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
DBUG_VOID_RETURN;
- if (!stmt->cursor || !stmt->cursor->is_open())
+ cursor= stmt->cursor;
+ if (!cursor || !cursor->is_open())
{
- my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0));
+ my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
DBUG_VOID_RETURN;
}
thd->current_arena= stmt;
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
- stmt->cursor->fetch(num_rows);
+ cursor->fetch(num_rows);
thd->protocol= &thd->protocol_simple; // Use normal protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
- thd->current_arena= thd;
-
- if (!stmt->cursor->is_open())
+ if (!cursor->is_open())
{
/* We're done with the fetch: reset PS for next execution */
cleanup_stmt_and_thd_after_use(stmt, thd);
reset_stmt_params(stmt);
+ /*
+ Must be the last, as some momory is still needed for
+ the previous calls.
+ */
+ free_root(cursor->mem_root, MYF(0));
}
+ thd->restore_backup_statement(stmt, &stmt_backup);
+ thd->current_arena= thd;
+
DBUG_VOID_RETURN;
}
@@ -2261,23 +2279,25 @@ void mysql_stmt_reset(THD *thd, char *packet)
/* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
+ Cursor *cursor;
DBUG_ENTER("mysql_stmt_reset");
statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
- if (stmt->cursor && stmt->cursor->is_open())
- stmt->cursor->close();
+ stmt->close_cursor(); /* will reset statement params */
+ cursor= stmt->cursor;
+ if (cursor && cursor->is_open())
+ {
+ thd->change_list= cursor->change_list;
+ cursor->close(FALSE);
+ cleanup_stmt_and_thd_after_use(stmt, thd);
+ free_root(cursor->mem_root, MYF(0));
+ }
stmt->state= Query_arena::PREPARED;
- /*
- Clear parameters from data which could be set by
- mysql_stmt_send_long_data() call.
- */
- reset_stmt_params(stmt);
-
mysql_reset_thd_for_next_command(thd);
send_ok(thd);
@@ -2290,13 +2310,13 @@ void mysql_stmt_reset(THD *thd, char *packet)
Note: we don't send any reply to that command.
*/
-void mysql_stmt_free(THD *thd, char *packet)
+void mysql_stmt_close(THD *thd, char *packet)
{
/* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
- DBUG_ENTER("mysql_stmt_free");
+ DBUG_ENTER("mysql_stmt_close");
statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
@@ -2385,7 +2405,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement::Prepared_statement(THD *thd_arg)
- :Statement(thd_arg),
+ :Statement(INITIALIZED, ++thd_arg->statement_id_counter,
+ thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size),
thd(thd_arg),
param_array(0),
param_count(0),
@@ -2423,8 +2445,17 @@ void Prepared_statement::setup_set_params()
Prepared_statement::~Prepared_statement()
{
if (cursor)
+ {
+ if (cursor->is_open())
+ {
+ cursor->close(FALSE);
+ free_items();
+ free_root(cursor->mem_root, MYF(0));
+ }
cursor->Cursor::~Cursor();
- free_items(free_list);
+ }
+ else
+ free_items();
delete lex->result;
}
@@ -2433,3 +2464,20 @@ Query_arena::Type Prepared_statement::type() const
{
return PREPARED_STATEMENT;
}
+
+
+void Prepared_statement::close_cursor()
+{
+ if (cursor && cursor->is_open())
+ {
+ thd->change_list= cursor->change_list;
+ cursor->close(FALSE);
+ cleanup_stmt_and_thd_after_use(this, thd);
+ free_root(cursor->mem_root, MYF(0));
+ }
+ /*
+ Clear parameters from data which could be set by
+ mysql_stmt_send_long_data() call.
+ */
+ reset_stmt_params(this);
+}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 8fe17198cf0..3880aa428b9 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -164,7 +164,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
ren_table->db, old_alias,
reg_ext);
unpack_filename(name, name);
- if ((table_type=get_table_type(name)) == DB_TYPE_UNKNOWN)
+ if ((table_type=get_table_type(thd, name)) == DB_TYPE_UNKNOWN)
{
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
if (!skip_error)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index cc0aa44d865..87ce26b24d5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -28,8 +28,6 @@
#include <hash.h>
#include <ft_global.h>
-typedef uint32 cache_rec_length_type;
-
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
"ref_or_null","unique_subquery","index_subquery",
@@ -87,10 +85,9 @@ static void update_depend_map(JOIN *join, ORDER *order);
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
bool change_list, bool *simple_order);
static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
- List<Item> &fields, bool send_row,
- uint select_options, const char *info,
- Item *having, Procedure *proc,
- SELECT_LEX_UNIT *unit);
+ List<Item> &fields, bool send_row,
+ uint select_options, const char *info,
+ Item *having);
static COND *build_equal_items(THD *thd, COND *cond,
COND_EQUAL *inherited,
List<TABLE_LIST> *join_list,
@@ -183,10 +180,10 @@ static void reset_cache_read(JOIN_CACHE *cache);
static void reset_cache_write(JOIN_CACHE *cache);
static void read_cached_record(JOIN_TAB *tab);
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
-static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &all_fields,ORDER *new_order);
-static ORDER *create_distinct_group(THD *thd, ORDER *order,
- List<Item> &fields,
+static bool setup_new_fields(THD *thd, List<Item> &fields,
+ List<Item> &all_fields, ORDER *new_order);
+static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
+ ORDER *order, List<Item> &fields,
bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
@@ -284,6 +281,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
save_allow_sum_func= thd->allow_sum_func;
thd->allow_sum_func= 0;
res= setup_conds(thd, tables, leaves, conds);
+
thd->allow_sum_func= save_allow_sum_func;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order);
@@ -340,11 +338,12 @@ 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, tables_list, &conds, &select_lex->leaf_tables,
+ setup_tables(thd, &select_lex->context,
+ tables_list, &conds, &select_lex->leaf_tables,
FALSE)) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
- setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
+ setup_fields(thd, (*rref_pointer_array), fields_list, 1,
&all_fields, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list,
select_lex->leaf_tables, fields_list,
@@ -360,7 +359,7 @@ JOIN::prepare(Item ***rref_pointer_array,
thd->allow_sum_func=1;
select_lex->having_fix_field= 1;
bool having_fix_rc= (!having->fixed &&
- (having->fix_fields(thd, tables_list, &having) ||
+ (having->fix_fields(thd, &having) ||
having->check_cols(1)));
select_lex->having_fix_field= 0;
if (having_fix_rc || thd->net.report_error)
@@ -433,7 +432,7 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err; /* purecov: inspected */
if (procedure)
{
- if (setup_new_fields(thd, tables_list, fields_list, all_fields,
+ if (setup_new_fields(thd, fields_list, all_fields,
procedure->param_fields))
goto err; /* purecov: inspected */
if (procedure->group)
@@ -567,7 +566,7 @@ JOIN::optimize()
Item_cond_and can't be fixed after creation, so we do not check
conds->fixed
*/
- conds->fix_fields(thd, tables_list, &conds);
+ conds->fix_fields(thd, &conds);
conds->change_ref_to_fields(thd, tables_list);
conds->top_level_item();
having= 0;
@@ -780,7 +779,8 @@ JOIN::optimize()
bool all_order_fields_used;
if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
- if ((group_list=create_distinct_group(thd, order, fields_list,
+ if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
+ order, fields_list,
&all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
@@ -1118,7 +1118,6 @@ int
JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
-
first_record= 0;
if (exec_tmp_table1)
@@ -1227,8 +1226,7 @@ JOIN::exec()
send_row_on_empty_set(),
select_options,
zero_result_cause,
- having, procedure,
- unit);
+ having);
DBUG_VOID_RETURN;
}
@@ -1437,7 +1435,7 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
end_read_record(&curr_join->join_tab->read_record);
- curr_join->const_tables= curr_join->tables; // Mark free for join_free()
+ curr_join->const_tables= curr_join->tables; // Mark free for cleanup()
curr_join->join_tab[0].table= 0; // Table is freed
// No sum funcs anymore
@@ -1667,9 +1665,9 @@ JOIN::exec()
*/
int
-JOIN::cleanup()
+JOIN::destroy()
{
- DBUG_ENTER("JOIN::cleanup");
+ DBUG_ENTER("JOIN::destroy");
select_lex->join= 0;
if (tmp_join)
@@ -1684,12 +1682,11 @@ JOIN::cleanup()
}
tmp_join->tmp_join= 0;
tmp_table_param.copy_field=0;
- DBUG_RETURN(tmp_join->cleanup());
+ DBUG_RETURN(tmp_join->destroy());
}
cond_equal= 0;
- lock=0; // It's faster to unlock later
- join_free(1);
+ cleanup(1);
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
@@ -1697,18 +1694,21 @@ JOIN::cleanup()
delete select;
delete_dynamic(&keyuse);
delete procedure;
- for (SELECT_LEX_UNIT *lex_unit= select_lex->first_inner_unit();
- lex_unit != 0;
- lex_unit= lex_unit->next_unit())
- {
- error|= lex_unit->cleanup();
- }
DBUG_RETURN(error);
}
/************************* Cursor ******************************************/
-
+
+Cursor::Cursor(THD *thd)
+ :Query_arena(&main_mem_root, INITIALIZED),
+ join(0), unit(0)
+{
+ /* We will overwrite it at open anyway. */
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+}
+
+
void
Cursor::init_from_thd(THD *thd)
{
@@ -1737,6 +1737,7 @@ Cursor::init_from_thd(THD *thd)
lock= thd->lock;
query_id= thd->query_id;
free_list= thd->free_list;
+ change_list= thd->change_list;
reset_thd(thd);
/*
XXX: thd->locked_tables is not changed.
@@ -1753,6 +1754,7 @@ Cursor::reset_thd(THD *thd)
thd->open_tables= 0;
thd->lock= 0;
thd->free_list= 0;
+ thd->change_list.empty();
}
@@ -1815,6 +1817,7 @@ Cursor::fetch(ulong num_rows)
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
enum_nested_loop_state error= NESTED_LOOP_OK;
+ Query_arena backup_arena;
DBUG_ENTER("Cursor::fetch");
DBUG_PRINT("enter",("rows: %lu", num_rows));
@@ -1825,8 +1828,9 @@ Cursor::fetch(ulong num_rows)
thd->open_tables= open_tables;
thd->lock= lock;
thd->query_id= query_id;
+ thd->change_list= change_list;
/* save references to memory, allocated during fetch */
- thd->set_n_backup_item_arena(this, &thd->stmt_backup);
+ thd->set_n_backup_item_arena(this, &backup_arena);
join->fetch_limit+= num_rows;
@@ -1841,10 +1845,8 @@ Cursor::fetch(ulong num_rows)
#ifdef USING_TRANSACTIONS
ha_release_temporary_latches(thd);
#endif
-
- thd->restore_backup_item_arena(this, &thd->stmt_backup);
- DBUG_ASSERT(thd->free_list == 0);
- reset_thd(thd);
+ /* Grab free_list here to correctly free it in close */
+ thd->restore_backup_item_arena(this, &backup_arena);
if (error == NESTED_LOOP_CURSOR_LIMIT)
{
@@ -1852,10 +1854,12 @@ Cursor::fetch(ulong num_rows)
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
::send_eof(thd);
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+ change_list= thd->change_list;
+ reset_thd(thd);
}
else
{
- close();
+ close(TRUE);
if (error == NESTED_LOOP_OK)
{
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
@@ -1870,22 +1874,23 @@ Cursor::fetch(ulong num_rows)
void
-Cursor::close()
+Cursor::close(bool is_active)
{
THD *thd= join->thd;
DBUG_ENTER("Cursor::close");
- join->join_free(0);
+ /*
+ In case of UNIONs JOIN is freed inside of unit->cleanup(),
+ otherwise in select_lex->cleanup().
+ */
if (unit)
- {
- /* In case of UNIONs JOIN is freed inside unit->cleanup() */
- unit->cleanup();
- }
+ (void) unit->cleanup();
+ else
+ (void) join->select_lex->cleanup();
+
+ if (is_active)
+ close_thread_tables(thd);
else
- {
- join->cleanup();
- delete join;
- }
{
/* XXX: Another hack: closing tables used in the cursor */
DBUG_ASSERT(lock || open_tables || derived_tables);
@@ -1904,23 +1909,12 @@ Cursor::close()
}
join= 0;
unit= 0;
- free_items(free_list);
- free_list= 0;
- /*
- Must be last, as some memory might be allocated for free purposes,
- like in free_tmp_table() (TODO: fix this issue)
- */
- free_root(mem_root, MYF(0));
+ free_items();
+ change_list.empty();
DBUG_VOID_RETURN;
}
-Cursor::~Cursor()
-{
- if (is_open())
- close();
-}
-
/*********************************************************************/
/*
@@ -1980,6 +1974,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
bool free_join= 1;
DBUG_ENTER("mysql_select");
+ select_lex->context.resolve_in_select_list= TRUE;
JOIN *join;
if (select_lex->join != 0)
{
@@ -2062,8 +2057,7 @@ err:
if (free_join)
{
thd->proc_info="end";
- err= join->cleanup();
- delete join;
+ err= select_lex->cleanup();
DBUG_RETURN(err || thd->net.report_error);
}
DBUG_RETURN(join->error);
@@ -5144,7 +5138,23 @@ inline void add_cond_and_fix(Item **e1, Item *e2)
(where othertbl is a non-const table and othertbl.field may be NULL)
and add them to conditions on correspoding tables (othertbl in this
example).
-
+
+ Exception from that is the case when referred_tab->join != join.
+ I.e. don't add NOT NULL constraints from any embedded subquery.
+ Consider this query:
+ SELECT A.f2 FROM t1 LEFT JOIN t2 A ON A.f2 = f1
+ WHERE A.f3=(SELECT MIN(f3) FROM t2 C WHERE A.f4 = C.f4) OR A.f3 IS NULL;
+ Here condition A.f3 IS NOT NULL is going to be added to the WHERE
+ condition of the embedding query.
+ Another example:
+ SELECT * FROM t10, t11 WHERE (t10.a < 10 OR t10.a IS NULL)
+ AND t11.b <=> t10.b AND (t11.a = (SELECT MAX(a) FROM t12
+ WHERE t12.b = t10.a ));
+ Here condition t10.a IS NOT NULL is going to be added.
+ In both cases addition of NOT NULL condition will erroneously reject
+ some rows of the result set.
+ referred_tab->join != join constraint would disallow such additions.
+
This optimization doesn't affect the choices that ref, range, or join
optimizer make. This was intentional because this was added after 4.1
was GA.
@@ -5175,11 +5185,19 @@ static void add_not_null_conds(JOIN *join)
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Item_field *not_null_item= (Item_field*)item;
JOIN_TAB *referred_tab= not_null_item->field->table->reginfo.join_tab;
- Item_func_isnotnull *notnull;
+ if (referred_tab->join != join)
+ continue;
+ Item *notnull;
if (!(notnull= new Item_func_isnotnull(not_null_item)))
DBUG_VOID_RETURN;
-
- notnull->quick_fix_field();
+ /*
+ We need to do full fix_fields() call here in order to have correct
+ notnull->const_item(). This is needed e.g. by test_quick_select
+ when it is called from make_join_select after this function is
+ called.
+ */
+ if (notnull->fix_fields(join->thd, &notnull))
+ DBUG_VOID_RETURN;
DBUG_EXECUTE("where",print_where(notnull,
referred_tab->table->alias););
add_cond_and_fix(&referred_tab->select_cond, notnull);
@@ -5896,29 +5914,68 @@ void JOIN_TAB::cleanup()
}
+void JOIN::join_free(bool full)
+{
+ SELECT_LEX_UNIT *unit;
+ SELECT_LEX *sl;
+ DBUG_ENTER("JOIN::join_free");
+
+ /*
+ Optimization: if not EXPLAIN and we are done with the JOIN,
+ free all tables.
+ */
+ full= full || (!select_lex->uncacheable && !thd->lex->describe);
+
+ cleanup(full);
+
+ for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
+ for (sl= unit->first_select_in_union(); sl; sl= sl->next_select())
+ {
+ JOIN *join= sl->join;
+ if (join)
+ join->join_free(full);
+ }
+
+ /*
+ We are not using tables anymore
+ Unlock all tables. We may be in an INSERT .... SELECT statement.
+ */
+ if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) &&
+ !select_lex->subquery_in_having &&
+ (select_lex == (thd->lex->unit.fake_select_lex ?
+ thd->lex->unit.fake_select_lex : &thd->lex->select_lex)))
+ {
+ /*
+ TODO: unlock tables even if the join isn't top level select in the
+ tree.
+ */
+ mysql_unlock_read_tables(thd, lock); // Don't free join->lock
+ lock= 0;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
/*
Free resources of given join
SYNOPSIS
- JOIN::join_free()
+ JOIN::cleanup()
fill - true if we should free all resources, call with full==1 should be
last, before it this function can be called with full==0
NOTE: with subquery this function definitely will be called several times,
but even for simple query it can be called several times.
*/
-void
-JOIN::join_free(bool full)
-{
- JOIN_TAB *tab,*end;
- DBUG_ENTER("JOIN::join_free");
- full= full || (!select_lex->uncacheable &&
- !thd->lex->subqueries &&
- !thd->lex->describe); // do not cleanup too early on EXPLAIN
+void JOIN::cleanup(bool full)
+{
+ DBUG_ENTER("JOIN::cleanup");
if (table)
{
+ JOIN_TAB *tab,*end;
/*
Only a sorted table may be cached. This sorted table is always the
first non const table in join->table
@@ -5929,16 +5986,6 @@ JOIN::join_free(bool full)
filesort_free_buffers(table[const_tables]);
}
- for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); unit;
- unit= unit->next_unit())
- {
- JOIN *join;
- for (SELECT_LEX *sl= unit->first_select_in_union(); sl;
- sl= sl->next_select())
- if ((join= sl->join))
- join->join_free(full);
- }
-
if (full)
{
for (tab= join_tab, end= tab+tables; tab != end; tab++)
@@ -5955,25 +6002,14 @@ JOIN::join_free(bool full)
}
}
}
-
/*
We are not using tables anymore
Unlock all tables. We may be in an INSERT .... SELECT statement.
*/
- if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) &&
- !select_lex->subquery_in_having)
- {
- // TODO: unlock tables even if the join isn't top level select in the tree
- if (select_lex == (thd->lex->unit.fake_select_lex ?
- thd->lex->unit.fake_select_lex : &thd->lex->select_lex))
- {
- mysql_unlock_read_tables(thd, lock); // Don't free join->lock
- lock=0;
- }
- }
-
if (full)
{
+ if (tmp_join)
+ tmp_table_param.copy_field= 0;
group_fields.delete_elements();
/*
We can't call delete_elements() on copy_funcs as this will cause
@@ -6208,8 +6244,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
static int
return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
List<Item> &fields, bool send_row, uint select_options,
- const char *info, Item *having, Procedure *procedure,
- SELECT_LEX_UNIT *unit)
+ const char *info, Item *having)
{
DBUG_ENTER("return_zero_rows");
@@ -6277,7 +6312,7 @@ public:
COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {}
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List<COND_CMP>;
template class I_List_iterator<COND_CMP>;
template class List<Item_func_match>;
@@ -7432,7 +7467,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
conds->top_level_item();
/* conds is always a new item as both cond and on_expr existed */
DBUG_ASSERT(!conds->fixed);
- conds->fix_fields(join->thd, 0, &conds);
+ conds->fix_fields(join->thd, &conds);
}
else
conds= table->on_expr;
@@ -7653,7 +7688,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
cond->fixed, also it do not need tables so we use 0 as second
argument.
*/
- cond->fix_fields(thd, 0, &cond);
+ cond->fix_fields(thd, &cond);
}
thd->insert_id(0); // Clear for next request
}
@@ -7672,7 +7707,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
cond->fixed, also it do not need tables so we use 0 as second
argument.
*/
- cond->fix_fields(thd, 0, &cond);
+ cond->fix_fields(thd, &cond);
}
}
}
@@ -7944,7 +7979,9 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table)
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
- bool group, bool modify_item, uint convert_blob_length)
+ bool group, bool modify_item,
+ bool table_cant_handle_bit_fields,
+ uint convert_blob_length)
{
switch (type) {
case Item::SUM_FUNC_ITEM:
@@ -7959,15 +7996,20 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::DEFAULT_VALUE_ITEM:
{
Item_field *field= (Item_field*) item;
+ if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT)
+ return create_tmp_field_from_item(thd, item, table, copy_func,
+ modify_item, convert_blob_length);
return create_tmp_field_from_field(thd, (*from_field= field->field),
item->name, table,
modify_item ? (Item_field*) item : NULL,
convert_blob_length);
}
case Item::REF_ITEM:
- if ( item->real_item()->type() == Item::FIELD_ITEM)
+ {
+ Item *tmp_item;
+ if ((tmp_item= item->real_item())->type() == Item::FIELD_ITEM)
{
- Item_field *field= (Item_field*) *((Item_ref*)item)->ref;
+ Item_field *field= (Item_field*) tmp_item;
Field *new_field= create_tmp_field_from_field(thd,
(*from_field= field->field),
item->name, table,
@@ -7977,6 +8019,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
item->set_result_field(new_field);
return new_field;
}
+ }
case Item::FUNC_ITEM:
case Item::COND_ITEM:
case Item::FIELD_AVG_ITEM:
@@ -8179,6 +8222,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
Field *new_field=
create_tmp_field(thd, table, arg, arg->type(), &copy_func,
tmp_from_field, group != 0,not_all_columns,
+ group || distinct,
param->convert_blob_length);
if (!new_field)
goto err; // Should be OOM
@@ -8189,6 +8233,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field++= (uint) (reg_field - table->field);
blob_count++;
}
+ new_field->field_index= (uint) (reg_field - table->field);
*(reg_field++)= new_field;
if (new_field->real_type() == MYSQL_TYPE_STRING ||
new_field->real_type() == MYSQL_TYPE_VARCHAR)
@@ -8226,7 +8271,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
create_tmp_field_for_schema(thd, item, table) :
create_tmp_field(thd, table, item, type, &copy_func,
tmp_from_field, group != 0,
- not_all_columns || group !=0,
+ not_all_columns || group != 0, 0,
param->convert_blob_length);
if (!new_field)
@@ -8254,6 +8299,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
new_field->flags|= GROUP_FLAG;
}
new_field->query_id= thd->query_id;
+ new_field->field_index= (uint) (reg_field - table->field);
*(reg_field++) =new_field;
}
if (!--hidden_field_count)
@@ -8364,6 +8410,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
field->move_field((char*) pos,(uchar*) 0,0);
+ if (field->type() == FIELD_TYPE_BIT)
+ {
+ /* We have to reserve place for extra bits among null bits */
+ ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8,
+ null_count & 7);
+ null_count+= (field->field_length & 7);
+ }
field->reset();
if (from_field[i])
{ /* Not a table Item */
@@ -11155,8 +11208,7 @@ static bool fix_having(JOIN *join, Item **having)
else // This should never happen
if (!(table->select->cond= new Item_cond_and(table->select->cond,
sort_table_cond)) ||
- table->select->cond->fix_fields(join->thd, join->tables_list,
- &table->select->cond))
+ table->select->cond->fix_fields(join->thd, &table->select->cond))
return 1;
table->select_cond=table->select->cond;
table->select_cond->top_level_item();
@@ -11606,7 +11658,7 @@ used_blob_length(CACHE_FIELD **ptr)
static bool
store_record_in_cache(JOIN_CACHE *cache)
{
- cache_rec_length_type length;
+ uint length;
uchar *pos;
CACHE_FIELD *copy,*end_field;
bool last_record;
@@ -11651,9 +11703,9 @@ store_record_in_cache(JOIN_CACHE *cache)
end > str && end[-1] == ' ' ;
end--) ;
length=(uint) (end-str);
- memcpy(pos+sizeof(length), str, length);
- memcpy_fixed(pos, &length, sizeof(length));
- pos+= length+sizeof(length);
+ memcpy(pos+2, str, length);
+ int2store(pos, length);
+ pos+= length+2;
}
else
{
@@ -11687,7 +11739,7 @@ static void
read_cached_record(JOIN_TAB *tab)
{
uchar *pos;
- cache_rec_length_type length;
+ uint length;
bool last_record;
CACHE_FIELD *copy,*end_field;
@@ -11716,10 +11768,10 @@ read_cached_record(JOIN_TAB *tab)
{
if (copy->strip)
{
- memcpy_fixed(&length, pos, sizeof(length));
- memcpy(copy->str, pos+sizeof(length), length);
+ length= uint2korr(pos);
+ memcpy(copy->str, pos+2, length);
memset(copy->str+length, ' ', copy->length-length);
- pos+= sizeof(length)+length;
+ pos+= 2 + length;
}
else
{
@@ -11756,10 +11808,10 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
for (store_key **copy=ref->key_copy ; *copy ; copy++)
{
- if ((*copy)->copy())
+ if ((*copy)->copy() & 1)
{
thd->count_cuted_fields= save_count_cuted_fields;
- return 1; // Something went wrong
+ return 1; // Something went wrong
}
}
thd->count_cuted_fields= save_count_cuted_fields;
@@ -11776,14 +11828,13 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
SYNOPSIS
find_order_in_list()
- 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
+ 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
DESCRIPTION
Given a column reference (represented by 'order') from a GROUP BY or ORDER
@@ -11800,6 +11851,8 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
RETURN
FALSE if OK
TRUE if error occurred
+
+ ref_pointer_array and all_fields are updated
*/
static bool
@@ -11845,26 +11898,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
original field name, we should additionaly check if we have conflict
for this name (in case if we would perform lookup in all tables).
*/
- if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables,
- order->item))
+ if (unaliased && !order_item->fixed &&
+ order_item->fix_fields(thd, order->item))
return TRUE;
/* Lookup the current GROUP field in the FROM clause. */
order_item_type= order_item->type();
+ from_field= (Field*) not_found_field;
if (is_group_field &&
order_item_type == Item::FIELD_ITEM ||
order_item_type == Item::REF_ITEM)
{
from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
- &view_ref, IGNORE_ERRORS, TRUE);
- if(!from_field)
- from_field= (Field*) not_found_field;
+ &view_ref, IGNORE_ERRORS, TRUE,
+ FALSE);
+ if (!from_field)
+ from_field= (Field*) not_found_field;
}
- else
- from_field= (Field*) not_found_field;
if (from_field == not_found_field ||
- from_field &&
(from_field != view_ref_found ?
/* it is field of base table => check that fields are same */
((*select_item)->type() == Item::FIELD_ITEM &&
@@ -11877,43 +11929,46 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
view_ref->type() == Item::REF_ITEM &&
((Item_ref *) (*select_item))->ref ==
((Item_ref *) view_ref)->ref)))
+ {
/*
- If there is no such field in the FROM clause, or it is the same field as
- the one found in the SELECT clause, then use the Item created for the
- SELECT field. As a result if there was a derived field that 'shadowed'
- a table field with the same name, the table field will be chosen over
- the derived field.
+ If there is no such field in the FROM clause, or it is the same field
+ as the one found in the SELECT clause, then use the Item created for
+ the SELECT field. As a result if there was a derived field that
+ 'shadowed' a table field with the same name, the table field will be
+ chosen over the derived field.
*/
- {
order->item= ref_pointer_array + counter;
order->in_field_list=1;
return FALSE;
}
else
+ {
/*
- There is a field with the same name in the FROM clause. This is the field
- that will be chosen. In this case we issue a warning so the user knows
- that the field from the FROM clause overshadows the column reference from
- the SELECT list.
+ There is a field with the same name in the FROM clause. This
+ is the field that will be chosen. In this case we issue a
+ warning so the user knows that the field from the FROM clause
+ overshadows the column reference from the SELECT list.
*/
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR,
ER(ER_NON_UNIQ_ERROR), from_field->field_name,
current_thd->where);
+ }
}
order->in_field_list=0;
/*
- The call to order_item->fix_fields() means that here we resolve 'order_item'
- to a column from a table in the list 'tables', or to a column in some outer
- query. Exactly because of the second case we come to this point even if
- (select_item == not_found_item), inspite of that fix_fields() calls
- find_item_in_list() one more time.
+ The call to order_item->fix_fields() means that here we resolve
+ 'order_item' to a column from a table in the list 'tables', or to
+ a column in some outer query. Exactly because of the second case
+ we come to this point even if (select_item == not_found_item),
+ inspite of that fix_fields() calls find_item_in_list() one more
+ time.
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
*/
if (!order_item->fixed &&
- (order_item->fix_fields(thd, tables, order->item) ||
+ (order_item->fix_fields(thd, order->item) ||
(order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
return TRUE; /* Wrong field. */
@@ -12025,7 +12080,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
*/
static bool
-setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+setup_new_fields(THD *thd, List<Item> &fields,
List<Item> &all_fields, ORDER *new_field)
{
Item **item;
@@ -12042,7 +12097,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
else
{
thd->where="procedure list";
- if ((*new_field->item)->fix_fields(thd, tables, new_field->item))
+ if ((*new_field->item)->fix_fields(thd, new_field->item))
DBUG_RETURN(1); /* purecov: inspected */
all_fields.push_front(*new_field->item);
new_field->item=all_fields.head_ref();
@@ -12058,12 +12113,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
*/
static ORDER *
-create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields,
+create_distinct_group(THD *thd, Item **ref_pointer_array,
+ ORDER *order_list, List<Item> &fields,
bool *all_order_by_fields_used)
{
List_iterator<Item> li(fields);
Item *item;
ORDER *order,*group,**prev;
+ uint index= 0;
*all_order_by_fields_used= 1;
while ((item=li++))
@@ -12095,11 +12152,17 @@ create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields,
ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord)
return 0;
- ord->item=li.ref();
+ /*
+ We have here only field_list (not all_field_list), so we can use
+ simple indexing of ref_pointer_array (order in the array and in the
+ list are same)
+ */
+ ord->item= ref_pointer_array + index;
ord->asc=1;
*prev=ord;
prev= &ord->next;
}
+ index++;
}
*prev=0;
return group;
@@ -12122,7 +12185,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
param->quick_group=1;
while ((field=li++))
{
- Item::Type type=field->type();
+ Item::Type type=field->real_item()->type();
if (type == Item::FIELD_ITEM)
param->field_count++;
else if (type == Item::SUM_FUNC_ITEM)
@@ -12136,7 +12199,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
for (uint i=0 ; i < sum_item->arg_count ; i++)
{
- if (sum_item->args[0]->type() == Item::FIELD_ITEM)
+ if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM)
param->field_count++;
else
param->func_count++;
@@ -12383,9 +12446,10 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
param->copy_funcs.empty();
for (i= 0; (pos= li++); i++)
{
- if (pos->type() == Item::FIELD_ITEM)
+ if (pos->real_item()->type() == Item::FIELD_ITEM)
{
Item_field *item;
+ pos= pos->real_item();
if (!(item= new Item_field(thd, ((Item_field*) pos))))
goto err;
pos= item;
@@ -12840,7 +12904,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
DBUG_RETURN(TRUE);
if (!cond->fixed)
- cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond);
+ cond->fix_fields(thd, (Item**)&cond);
if (join_tab->select)
{
error=(int) cond->add(join_tab->select->cond);
@@ -12882,8 +12946,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select)
thd reference to the context
expr expression to make replacement
group_list list of references to group by items
- changed out: returns 1 if item contains a replaced field item
-
+ changed out: returns 1 if item contains a replaced field item
+
DESCRIPTION
The function replaces occurrences of group by fields in expr
by ref objects for these fields unless they are under aggregate
@@ -12912,6 +12976,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
{
if (expr->arg_count)
{
+ Name_resolution_context *context= &thd->lex->current_select->context;
Item **arg,**arg_end;
for (arg= expr->arguments(),
arg_end= expr->arguments()+expr->arg_count;
@@ -12925,8 +12990,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
{
if (item->eq(*group_tmp->item,0))
{
- Item *new_item;
- if(!(new_item= new Item_ref(group_tmp->item, 0, item->name)))
+ Item *new_item;
+ if(!(new_item= new Item_ref(context, group_tmp->item, 0,
+ item->name)))
return 1; // fatal_error is set
thd->change_item_tree(arg, new_item);
*changed= TRUE;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 5bec06fa36c..9285e33be33 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -325,7 +325,7 @@ class JOIN :public Sql_alloc
int optimize();
int reinit();
void exec();
- int cleanup();
+ int destroy();
void restore_tmp();
bool alloc_func_list();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
@@ -349,7 +349,15 @@ class JOIN :public Sql_alloc
int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
bool test_in_subselect(Item **where);
+ /*
+ Release memory and, if possible, the open tables held by this execution
+ plan (and nested plans). It's used to release some tables before
+ the end of execution in order to increase concurrency and reduce
+ memory consumption.
+ */
void join_free(bool full);
+ /* Cleanup this JOIN, possibly for reuse */
+ void cleanup(bool full);
void clear();
bool save_join_tab();
bool send_row_on_empty_set()
@@ -372,6 +380,7 @@ class JOIN :public Sql_alloc
class Cursor: public Sql_alloc, public Query_arena
{
+ MEM_ROOT main_mem_root;
JOIN *join;
SELECT_LEX_UNIT *unit;
@@ -381,6 +390,7 @@ class Cursor: public Sql_alloc, public Query_arena
/* List of items created during execution */
query_id_t query_id;
public:
+ Item_change_list change_list;
select_send result;
/* Temporary implementation as now we replace THD state by value */
@@ -393,11 +403,12 @@ public:
void fetch(ulong num_rows);
void reset() { join= 0; }
bool is_open() const { return join != 0; }
- void close();
+
+ void close(bool is_active);
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
- Cursor() :Query_arena(TRUE), join(0), unit(0) {}
- ~Cursor();
+ Cursor(THD *thd);
+ ~Cursor() {}
};
@@ -447,6 +458,7 @@ class store_key :public Sql_alloc
char *null_ptr;
char err;
public:
+ enum store_key_result { STORE_KEY_OK, STORE_KEY_FATAL, STORE_KEY_CONV };
store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
:null_ptr(null),err(0)
{
@@ -462,7 +474,7 @@ class store_key :public Sql_alloc
ptr, (uchar*) null, 1);
}
virtual ~store_key() {} /* Not actually needed */
- virtual bool copy()=0;
+ virtual enum store_key_result copy()=0;
virtual const char *name() const=0;
};
@@ -483,10 +495,10 @@ class store_key_field: public store_key
copy_field.set(to_field,from_field,0);
}
}
- bool copy()
+ enum store_key_result copy()
{
copy_field.do_copy(&copy_field);
- return err != 0;
+ return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK;
}
const char *name() const { return field_name; }
};
@@ -503,9 +515,11 @@ public:
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
&err : NullS, length), item(item_arg)
{}
- bool copy()
+ enum store_key_result copy()
{
- return item->save_in_field_no_warnings(to_field, 1) || err != 0;
+ int res= item->save_in_field(to_field, 1);
+ return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res);
+
}
const char *name() const { return "func"; }
};
@@ -523,15 +537,19 @@ public:
&err : NullS, length, item_arg), inited(0)
{
}
- bool copy()
+ enum store_key_result copy()
{
+ int res;
if (!inited)
{
inited=1;
- if (item->save_in_field(to_field, 1))
- err= 1;
+ if ((res= item->save_in_field(to_field, 1)))
+ {
+ if (!err)
+ err= res;
+ }
}
- return err != 0;
+ return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
}
const char *name() const { return "const"; }
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index aaa34dc4cb7..8343f9ec582 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -347,6 +347,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->table_name));
+ /* We want to preserve the tree for views. */
+ 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))
{
@@ -1068,7 +1071,13 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
buff->append('.');
append_identifier(thd, buff, table->view_name.str, table->view_name.length);
buff->append(" AS ", 4);
- buff->append(table->query.str, table->query.length);
+
+ /*
+ We can't just use table->query, because our SQL_MODE may trigger
+ a different syntax, like when ANSI_QUOTES is defined.
+ */
+ table->view->unit.print(buff);
+
if (table->with_check != VIEW_CHECK_NONE)
{
if (table->with_check == VIEW_CHECK_LOCAL)
@@ -1102,7 +1111,7 @@ public:
char *query;
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List<thread_info>;
#endif
@@ -3240,11 +3249,13 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
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++)
{
if (field_info->old_name)
{
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (field)
{
field->set_name(field_info->old_name,
@@ -3264,12 +3275,14 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
char tmp[128];
LEX *lex= thd->lex;
SELECT_LEX *sel= lex->current_select;
+ Name_resolution_context *context= &sel->context;
if (!sel->item_list.elements)
{
ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
String buffer(tmp,sizeof(tmp), system_charset_info);
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (!field || add_item_to_list(thd, field))
return 1;
buffer.length(0);
@@ -3291,6 +3304,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
char tmp[128];
String buffer(tmp,sizeof(tmp), thd->charset());
LEX *lex= thd->lex;
+ Name_resolution_context *context= &lex->select_lex.context;
ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
buffer.length(0);
@@ -3302,7 +3316,8 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
buffer.append(lex->wild->ptr());
buffer.append(")");
}
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (add_item_to_list(thd, field))
return 1;
field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
@@ -3310,7 +3325,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
field_info= &schema_table->fields_info[3];
- field= new Item_field(NullS, NullS, field_info->field_name);
+ field= new Item_field(context, NullS, NullS, field_info->field_name);
if (add_item_to_list(thd, field))
return 1;
field->set_name(field_info->old_name, strlen(field_info->old_name),
@@ -3325,6 +3340,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
+ Name_resolution_context *context= &thd->lex->select_lex.context;
+
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
@@ -3332,7 +3349,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
*field_num == 17 ||
*field_num == 18))
continue;
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (field)
{
field->set_name(field_info->old_name,
@@ -3351,10 +3369,13 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {0, 2, 1, 3, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
+ Name_resolution_context *context= &thd->lex->select_lex.context;
+
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (field)
{
field->set_name(field_info->old_name,
@@ -3373,10 +3394,13 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
+ Name_resolution_context *context= &thd->lex->select_lex.context;
+
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ Item_field *field= new Item_field(context,
+ NullS, NullS, field_info->field_name);
if (field)
{
field->set_name(field_info->old_name,
@@ -3442,12 +3466,11 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
if (table_list->field_translation)
{
- Field_translator *end= table_list->field_translation +
- sel->item_list.elements;
+ Field_translator *end= table_list->field_translation_end;
for (transl= table_list->field_translation; transl < end; transl++)
{
if (!transl->item->fixed &&
- transl->item->fix_fields(thd, table_list, &transl->item))
+ transl->item->fix_fields(thd, &transl->item))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -3464,11 +3487,12 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
{
char *name= item->name;
transl[i].item= item;
- if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item))
+ if (!item->fixed && item->fix_fields(thd, &transl[i].item))
DBUG_RETURN(1);
transl[i++].name= name;
}
table_list->field_translation= transl;
+ table_list->field_translation_end= transl + sel->item_list.elements;
}
DBUG_RETURN(0);
@@ -3495,7 +3519,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx);
LEX_STRING db, table;
DBUG_ENTER("mysql_schema_select");
- /*
+ /*
We have to make non const db_name & table_name
because of lower_case_table_names
*/
@@ -3503,7 +3527,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
information_schema_name.length, 0);
make_lex_string(thd, &table, schema_table->table_name,
strlen(schema_table->table_name), 0);
- if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
+ if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
0, 0, TL_READ, (List<String> *) 0,
(List<String> *) 0))
@@ -3879,7 +3903,7 @@ ST_SCHEMA_TABLE schema_tables[]=
};
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator_fast<char>;
template class List<char>;
#endif
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 8a29c481dc1..89282d9fcb9 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -39,6 +39,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted);
static bool prepare_blob_field(THD *thd, create_field *sql_field);
+static bool check_engine(THD *thd, const char *table_name,
+ enum db_type *new_engine);
/*
@@ -254,21 +256,22 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
build_table_path(path, sizeof(path), db, alias, reg_ext);
}
if (drop_temporary ||
- (access(path,F_OK) &&
- ha_create_table_from_engine(thd,db,alias,TRUE)) ||
+ (access(path,F_OK) &&
+ ha_create_table_from_engine(thd,db,alias)) ||
(!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE))
{
+ // Table was not found on disk and table can't be created from engine
if (if_exists)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
table->table_name);
else
- error= 1;
+ error= 1;
}
else
{
char *end;
- db_type table_type= get_table_type(path);
+ db_type table_type= get_table_type(thd, path);
*(end=fn_ext(path))=0; // Remove extension for delete
error= ha_delete_table(thd, table_type, path, table->table_name,
!dont_log_query);
@@ -749,10 +752,15 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
Convert the default value from client character
set into the column character set if necessary.
*/
- if (sql_field->def)
+ if (sql_field->def && cs != sql_field->def->collation.collation)
{
- sql_field->def=
- sql_field->def->safe_charset_converter(cs);
+ if (!(sql_field->def=
+ sql_field->def->safe_charset_converter(cs)))
+ {
+ /* Could not convert */
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(-1);
+ }
}
if (sql_field->sql_type == FIELD_TYPE_SET)
@@ -1490,7 +1498,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
KEY *key_info_buffer;
handler *file;
bool error= TRUE;
- enum db_type new_db_type;
DBUG_ENTER("mysql_create_table");
/* Check for duplicate fields and check type of table to create */
@@ -1500,16 +1507,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0));
DBUG_RETURN(TRUE);
}
- if ((new_db_type= ha_checktype(create_info->db_type)) !=
- create_info->db_type)
- {
- create_info->db_type= new_db_type;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_storage_engine(new_db_type),
- table_name);
- }
+ if (check_engine(thd, table_name, &create_info->db_type))
+ DBUG_RETURN(TRUE);
db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
db_options|=HA_OPTION_PACK_RECORD;
@@ -1556,14 +1555,12 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
- char tmp_table_name[tmp_file_prefix_length+22+22+22+3];
- my_snprintf(tmp_table_name, sizeof(tmp_table_name), "%s%lx_%lx_%x",
- tmp_file_prefix, current_pid, thd->thread_id,
- thd->tmp_table++);
+ my_snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s",
+ mysql_tmpdir, tmp_file_prefix, current_pid, thd->thread_id,
+ thd->tmp_table++, reg_ext);
if (lower_case_table_names)
- my_casedn_str(files_charset_info, tmp_table_name);
+ my_casedn_str(files_charset_info, path);
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
- build_table_path(path, sizeof(path), db, tmp_table_name, reg_ext);
}
else
build_table_path(path, sizeof(path), db, alias, reg_ext);
@@ -1611,15 +1608,14 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
{
bool create_if_not_exists =
create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
- if (!ha_create_table_from_engine(thd, db, table_name,
- create_if_not_exists))
+ if (ha_table_exists_in_engine(thd, db, table_name))
{
- DBUG_PRINT("info", ("Table already existed in handler"));
+ DBUG_PRINT("info", ("Table with same name already existed in handler"));
if (create_if_not_exists)
{
- create_info->table_existed= 1; // Mark that table existed
- error= FALSE;
+ create_info->table_existed= 1; // Mark that table existed
+ error= FALSE;
}
else
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
@@ -1740,7 +1736,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
field=item->tmp_table_field(&tmp_table);
else
field=create_tmp_field(thd, &tmp_table, item, item->type(),
- (Item ***) 0, &tmp_field,0,0,0);
+ (Item ***) 0, &tmp_field, 0, 0, 0, 0);
if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
((Item_field *)item)->field :
@@ -1769,7 +1765,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
create_info, *extra_fields, *keys, 0,
select_field_count))
{
- if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0)))
+ if (!(table= open_table(thd, create_table, thd->mem_root, (bool*)0, 0)))
quick_rm_table(create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name));
}
@@ -2110,6 +2106,7 @@ end:
}
+
/*
RETURN VALUES
FALSE Message sent to net (admin operation went ok)
@@ -2129,10 +2126,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT *),
int (view_operator_func)(THD *, TABLE_LIST*))
{
- TABLE_LIST *table, *next_global_table;
+ TABLE_LIST *table, *save_next_global, *save_next_local;
+ SELECT_LEX *select= &thd->lex->select_lex;
List<Item> field_list;
Item *item;
Protocol *protocol= thd->protocol;
+ LEX *lex= thd->lex;
int result_code;
DBUG_ENTER("mysql_admin_table");
@@ -2159,12 +2158,25 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
thd->open_options|= extra_open_options;
table->lock_type= lock_type;
/* open only one table from local list of command */
- next_global_table= table->next_global;
+ save_next_global= table->next_global;
table->next_global= 0;
+ save_next_local= table->next_local;
+ table->next_local= 0;
+ select->table_list.first= (byte*)table;
+ /*
+ Time zone tables and SP tables can be add to lex->query_tables list,
+ so it have to be prepared.
+ TODO: Investigate if we can put extra tables into argument instead of
+ using lex->query_tables
+ */
+ lex->query_tables= table;
+ lex->query_tables_last= &table->next_global;
+ lex->query_tables_own_last= 0;;
thd->no_warnings_for_error= no_warnings_for_error;
open_and_lock_tables(thd, table);
thd->no_warnings_for_error= 0;
- table->next_global= next_global_table;
+ table->next_global= save_next_global;
+ table->next_local= save_next_local;
/* if view are unsupported */
if (table->view && view_operator_func == NULL)
{
@@ -2212,7 +2224,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
err_msg= (const char *)buf;
}
protocol->store(err_msg, system_charset_info);
+ lex->cleanup_after_one_table_open();
thd->clear_error();
+ /*
+ View opening can be interrupted in the middle of process so some
+ tables can be left opening
+ */
+ close_thread_tables(thd);
if (protocol->write())
goto err;
continue;
@@ -2281,6 +2299,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
send_result:
+ lex->cleanup_after_one_table_open();
thd->clear_error(); // these errors shouldn't get client
protocol->prepare_for_resend();
protocol->store(table_name, system_charset_info);
@@ -2408,13 +2427,6 @@ send_result_message:
}
close_thread_tables(thd);
table->table=0; // For query cache
- /*
- thd->lex->derived_tables may be set to non zero value if we open
- a view. It is necessary to clear thd->lex->derived_tables flag
- to prevent processing of derived tables during next open_and_lock_tables
- if next table is a real table.
- */
- thd->lex->derived_tables= 0;
if (protocol->write())
goto err;
}
@@ -3125,16 +3137,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
old_db_type= table->s->db_type;
if (create_info->db_type == DB_TYPE_DEFAULT)
create_info->db_type= old_db_type;
- if ((new_db_type= ha_checktype(create_info->db_type)) !=
- create_info->db_type)
- {
- create_info->db_type= new_db_type;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_USING_OTHER_HANDLER,
- ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_storage_engine(new_db_type),
- new_name);
- }
+ if (check_engine(thd, new_name, &create_info->db_type))
+ DBUG_RETURN(TRUE);
+ new_db_type= create_info->db_type;
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type= table->s->row_type;
@@ -3413,7 +3418,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
*/
if (!Field::type_can_have_key_part(cfield->field->type()) ||
!Field::type_can_have_key_part(cfield->sql_type) ||
- cfield->field->field_length == key_part_length ||
+ (cfield->field->field_length == key_part_length &&
+ !f_is_blob(key_part->key_type)) ||
(cfield->length && (cfield->length < key_part_length /
key_part->field->charset()->mbmaxlen)))
key_part_length= 0; // Use whole field
@@ -3570,7 +3576,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
bzero((void*) &tbl, sizeof(tbl));
tbl.db= new_db;
tbl.table_name= tbl.alias= tmp_name;
- new_table= open_table(thd, &tbl, thd->mem_root, 0);
+ new_table= open_table(thd, &tbl, thd->mem_root, 0, 0);
}
else
{
@@ -4132,3 +4138,24 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
table->table=0;
DBUG_RETURN(TRUE);
}
+
+static bool check_engine(THD *thd, const char *table_name,
+ enum db_type *new_engine)
+{
+ enum db_type req_engine= *new_engine;
+ bool no_substitution=
+ test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
+ if ((*new_engine=
+ ha_checktype(thd, req_engine, no_substitution, 1)) == DB_TYPE_UNKNOWN)
+ return TRUE;
+
+ if (req_engine != *new_engine)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_USING_OTHER_HANDLER,
+ ER(ER_WARN_USING_OTHER_HANDLER),
+ ha_get_storage_engine(*new_engine),
+ table_name);
+ }
+ return FALSE;
+}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 95524a6dfbf..fd79fc8b878 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1,3 +1,20 @@
+/* Copyright (C) 2004-2005 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 "mysql_priv.h"
#include "sp_head.h"
#include "sql_trigger.h"
@@ -52,7 +69,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
But do we want this ?
*/
- if (open_and_lock_tables(thd, tables))
+ /* We should have only one table in table list. */
+ DBUG_ASSERT(tables->next_global == 0);
+
+ if (!(table= open_ltable(thd, tables, tables->lock_type)))
DBUG_RETURN(TRUE);
/*
@@ -63,8 +83,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
if (check_global_access(thd, SUPER_ACL))
DBUG_RETURN(TRUE);
- table= tables->table;
-
/*
We do not allow creation of triggers on views or temporary tables.
We have to do this check here and not in
@@ -201,7 +219,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
{
trg_field->setup_field(thd, table);
if (!trg_field->fixed &&
- trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0))
+ trg_field->fix_fields(thd, (Item **)0))
return 1;
}
@@ -418,6 +436,18 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
table->triggers= triggers;
/*
+ Construct key that will represent triggers for this table in the set
+ of routines used by statement.
+ */
+ triggers->sroutines_key.length= 1+strlen(db)+1+strlen(table_name)+1;
+ if (!(triggers->sroutines_key.str=
+ alloc_root(&table->mem_root, triggers->sroutines_key.length)))
+ DBUG_RETURN(1);
+ triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER;
+ strmov(strmov(strmov(triggers->sroutines_key.str+1, db), "."),
+ table_name);
+
+ /*
TODO: This could be avoided if there is no triggers
for UPDATE and DELETE.
*/
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 0547283d0c5..044219d5ac9 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -1,3 +1,20 @@
+/* Copyright (C) 2004-2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
/*
This class holds all information about triggers of table.
@@ -28,6 +45,14 @@ class Table_triggers_list: public Sql_alloc
used in CREATE/DROP TRIGGER for looking up trigger by name.
*/
List<LEX_STRING> names_list;
+ /*
+ Key representing triggers for this table in set of all stored
+ routines used by statement.
+ TODO: We won't need this member once triggers namespace will be
+ database-wide instead of table-wide because then we will be able
+ to use key based on sp_name as for other stored routines.
+ */
+ LEX_STRING sroutines_key;
public:
/*
@@ -112,6 +137,8 @@ public:
}
friend class Item_trigger_field;
+ friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
+ Table_triggers_list *triggers);
private:
bool prepare_record1_accessors(TABLE *table);
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 4df3fe0949d..d588572a762 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -65,8 +65,8 @@ class udf_handler :public Sql_alloc
Item_result result_type () const
{ return u_d ? u_d->returns : STRING_RESULT;}
bool get_arguments();
- bool fix_fields(THD *thd,struct st_table_list *tlist,Item_result_field *item,
- uint arg_count,Item **args);
+ bool fix_fields(THD *thd, Item_result_field *item,
+ uint arg_count, Item **args);
void cleanup();
double val(my_bool *null_value)
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index f59d7fffe85..f2b637dc5f4 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -124,6 +124,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
&result_table_list.next_local);
+ for (ORDER *order= (ORDER *)global_parameters->order_list.first;
+ order;
+ order=order->next)
+ {
+ (*order->item)->walk(&Item::change_context_processor,
+ (byte *) &fake_select_lex->context);
+ }
}
@@ -187,6 +194,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
else
tmp_result= sel_result;
+ sl->context.resolve_in_select_list= TRUE;
+
for (;sl; sl= sl->next_select())
{
bool can_skip_order_by;
@@ -448,7 +457,9 @@ bool st_select_lex_unit::exec()
table->no_keyread=1;
}
res= sl->join->error;
- offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : 0;
+ offset_limit_cnt= (ha_rows)(sl->offset_limit ?
+ sl->offset_limit->val_uint() :
+ 0);
if (!res)
{
examined_rows+= thd->examined_row_count;
@@ -553,7 +564,6 @@ bool st_select_lex_unit::exec()
bool st_select_lex_unit::cleanup()
{
int error= 0;
- JOIN *join;
DBUG_ENTER("st_select_lex_unit::cleanup");
if (cleaned)
@@ -572,29 +582,17 @@ bool st_select_lex_unit::cleanup()
}
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
+ error|= sl->cleanup();
+
+ if (fake_select_lex)
{
- if ((join= sl->join))
- {
- error|= sl->join->cleanup();
- delete join;
- }
- else
+ JOIN *join;
+ if ((join= fake_select_lex->join))
{
- // it can be DO/SET with subqueries
- for (SELECT_LEX_UNIT *lex_unit= sl->first_inner_unit();
- lex_unit != 0;
- lex_unit= lex_unit->next_unit())
- {
- error|= lex_unit->cleanup();
- }
+ join->tables_list= 0;
+ join->tables= 0;
}
- }
- if (fake_select_lex && (join= fake_select_lex->join))
- {
- join->tables_list= 0;
- join->tables= 0;
- error|= join->cleanup();
- delete join;
+ error|= fake_select_lex->cleanup();
}
DBUG_RETURN(error);
@@ -650,3 +648,25 @@ bool st_select_lex_unit::change_result(select_subselect *result,
res= fake_select_lex->join->change_result(result);
return (res);
}
+
+
+bool st_select_lex::cleanup()
+{
+ bool error= FALSE;
+ DBUG_ENTER("st_select_lex::cleanup()");
+
+ if (join)
+ {
+ DBUG_ASSERT((st_select_lex*)join->select_lex == this);
+ error= join->destroy();
+ delete join;
+ join= 0;
+ }
+ for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
+ lex_unit= lex_unit->next_unit())
+ {
+ error= (bool) ((uint) error | (uint) lex_unit->cleanup());
+ }
+ DBUG_RETURN(error);
+}
+
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6b9a8ddfcb6..8a5b4ad8eae 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -67,6 +67,8 @@ static bool check_fields(THD *thd, List<Item> &items)
List_iterator<Item> it(items);
Item *item;
Item_field *field;
+ Name_resolution_context *context= &thd->lex->select_lex.context;
+
while ((item= it++))
{
if (!(field= item->filed_for_view_update()))
@@ -185,14 +187,8 @@ int mysql_update(THD *thd,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
#endif
- {
- bool res;
- select_lex->no_wrap_view_item= 1;
- res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
- select_lex->no_wrap_view_item= 0;
- if (res)
- DBUG_RETURN(1); /* purecov: inspected */
- }
+ if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0))
+ DBUG_RETURN(1); /* purecov: inspected */
if (table_list->view && check_fields(thd, fields))
{
DBUG_RETURN(1);
@@ -216,7 +212,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, 0, table_list, values, 1, 0, 0))
+ if (setup_fields(thd, 0, values, 1, 0, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -341,6 +337,8 @@ int mysql_update(THD *thd,
break;
}
}
+ else
+ table->file->unlock_row();
}
if (thd->killed && !error)
error= 1; // Aborted
@@ -557,7 +555,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) ||
+ if (setup_tables(thd, &select_lex->context,
+ table_list, conds, &select_lex->leaf_tables,
+ FALSE) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
select_lex->setup_ref_array(thd, order_num) ||
setup_order(thd, select_lex->ref_pointer_array,
@@ -617,7 +617,6 @@ bool mysql_multi_update_prepare(THD *thd)
TABLE_LIST *tl, *leaves;
List<Item> *fields= &lex->select_lex.item_list;
table_map tables_for_update;
- int res;
bool update_view= 0;
/*
if this multi-update was converted from usual update, here is table
@@ -642,15 +641,12 @@ bool mysql_multi_update_prepare(THD *thd)
call in setup_tables()).
*/
- if (setup_tables(thd, table_list, &lex->select_lex.where,
+ if (setup_tables(thd, &lex->select_lex.context,
+ table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, FALSE))
DBUG_RETURN(TRUE);
- leaves= lex->select_lex.leaf_tables;
- if ((lex->select_lex.no_wrap_view_item= 1,
- res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
- lex->select_lex.no_wrap_view_item= 0,
- res))
+ if (setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0))
DBUG_RETURN(TRUE);
for (tl= table_list; tl ; tl= tl->next_local)
@@ -672,6 +668,7 @@ bool mysql_multi_update_prepare(THD *thd)
/*
Setup timestamp handling and locking mode
*/
+ leaves= lex->select_lex.leaf_tables;
for (tl= leaves; tl; tl= tl->next_leaf)
{
TABLE *table= tl->table;
@@ -762,12 +759,10 @@ bool mysql_multi_update_prepare(THD *thd)
for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
tbl->cleanup_items();
- if (setup_tables(thd, table_list, &lex->select_lex.where,
+ if (setup_tables(thd, &lex->select_lex.context,
+ table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, FALSE) ||
- (lex->select_lex.no_wrap_view_item= 1,
- res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
- lex->select_lex.no_wrap_view_item= 0,
- res))
+ setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0))
DBUG_RETURN(TRUE);
}
@@ -897,7 +892,7 @@ int multi_update::prepare(List<Item> &not_used_values,
reference tables
*/
- if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0))
+ if (setup_fields(thd, 0, *values, 1, 0, 0))
DBUG_RETURN(1);
/*
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 5152619fd85..a60bf80a6d8 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -20,6 +20,7 @@
#include "parse_file.h"
#include "sp.h"
#include "sp_head.h"
+#include "sp_cache.h"
#define MD5_BUFF_LENGTH 33
@@ -36,6 +37,62 @@ TYPELIB updatable_views_with_limit_typelib=
/*
+ Make a unique name for an anonymous view column
+ SYNOPSIS
+ target reference to the item for which a new name has to be made
+ item_list list of items within which we should check uniqueness of
+ the created name
+ last_element the last element of the list above
+
+ NOTE
+ Unique names are generated by adding 'My_exp_' to the old name of the
+ column. In case the name that was created this way already exists, we
+ add a numeric postfix to its end (i.e. "1") and increase the number
+ until the name becomes unique. If the generated name is longer than
+ NAME_LEN, it is truncated.
+*/
+
+static void make_unique_view_field_name(Item *target,
+ List<Item> &item_list,
+ Item *last_element)
+{
+ char *name= (target->orig_name ?
+ target->orig_name :
+ target->name);
+ uint name_len, attempt;
+ char buff[NAME_LEN+1];
+ List_iterator_fast<Item> itc(item_list);
+
+ for (attempt= 0;; attempt++)
+ {
+ Item *check;
+ bool ok= TRUE;
+
+ if (attempt)
+ name_len= my_snprintf(buff, NAME_LEN, "My_exp_%d_%s", attempt, name);
+ else
+ name_len= my_snprintf(buff, NAME_LEN, "My_exp_%s", name);
+
+ do
+ {
+ check= itc++;
+ if (check != target &&
+ my_strcasecmp(system_charset_info, buff, check->name) == 0)
+ {
+ ok= FALSE;
+ break;
+ }
+ } while (check != last_element);
+ if (ok)
+ break;
+ itc.rewind();
+ }
+
+ target->orig_name= target->name;
+ target->set_name(buff, name_len, system_charset_info);
+}
+
+/*
Creating/altering VIEW procedure
SYNOPSIS
@@ -85,6 +142,9 @@ bool mysql_create_view(THD *thd,
goto err;
}
+ if (mode != VIEW_CREATE_NEW)
+ sp_cache_invalidate();
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Privilege check for view creation:
@@ -240,24 +300,37 @@ bool mysql_create_view(THD *thd,
goto err;
}
while ((item= it++, name= nm++))
+ {
item->set_name(name->str, name->length, system_charset_info);
+ item->is_autogenerated_name= FALSE;
+ }
}
/* Test absence of duplicates names */
{
Item *item;
List_iterator_fast<Item> it(select_lex->item_list);
- it++;
+ List_iterator_fast<Item> itc(select_lex->item_list);
while ((item= it++))
{
Item *check;
- List_iterator_fast<Item> itc(select_lex->item_list);
+ /* 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 (strcmp(item->name, check->name) == 0)
+ if (my_strcasecmp(system_charset_info, item->name, check->name) == 0)
{
- my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
- DBUG_RETURN(TRUE);
+ 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);
+ }
}
}
}
@@ -755,16 +828,30 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
old_lex->can_use_merged()) &&
!old_lex->can_not_use_merged())
{
+ List_iterator_fast<TABLE_LIST> ti(view_select->top_join_list);
/* lex should contain at least one table */
DBUG_ASSERT(view_tables != 0);
table->effective_algorithm= VIEW_ALGORITHM_MERGE;
DBUG_PRINT("info", ("algorithm: MERGE"));
table->updatable= (table->updatable_view != 0);
- table->effective_with_check= (uint8)table->with_check;
-
- table->ancestor= view_tables;
-
+ table->effective_with_check=
+ old_lex->get_effective_with_check(table);
+
+ /* prepare view context */
+ lex->select_lex.context.resolve_in_table_list_only(table->ancestor=
+ view_tables);
+ lex->select_lex.context.outer_context= 0;
+ lex->select_lex.context.select_lex= table->select_lex;
+ /* do not check privileges & hide errors for view underlyings */
+ for (SELECT_LEX *sl= lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ sl->context.check_privileges= FALSE;
+ sl->context.error_processor= &view_error_processor;
+ sl->context.error_processor_data= (void *)table;
+ }
/*
Tables of the main select of the view should be marked as belonging
to the same select as original view (again we can use LEX::select_lex
@@ -785,13 +872,11 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
nested_join->join_list= view_select->top_join_list;
/* re-nest tables of VIEW */
+ ti.rewind();
+ while ((tbl= ti++))
{
- List_iterator_fast<TABLE_LIST> ti(nested_join->join_list);
- while ((tbl= ti++))
- {
- tbl->join_list= &nested_join->join_list;
- tbl->embedding= table;
- }
+ tbl->join_list= &nested_join->join_list;
+ tbl->embedding= table;
}
}
@@ -799,13 +884,12 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->where= view_select->where;
/*
Add subqueries units to SELECT into which we merging current view.
-
unit(->next)* chain starts with subqueries that are used by this
view and continues with subqueries that are used by other views.
We must not add any subquery twice (otherwise we'll form a loop),
- to do this we remember in end_unit the first subquery that has
+ to do this we remember in end_unit the first subquery that has
been already added.
-
+
NOTE: we do not support UNION here, so we take only one select
*/
SELECT_LEX_NODE *end_unit= table->select_lex->slave;
@@ -920,6 +1004,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
if (my_delete(path, MYF(MY_WME)))
goto err;
query_cache_invalidate3(thd, view, 0);
+ sp_cache_invalidate();
VOID(pthread_mutex_unlock(&LOCK_open));
}
send_ok(thd);
@@ -991,9 +1076,9 @@ frm_type_enum mysql_frm_type(char *path)
bool check_key_in_view(THD *thd, TABLE_LIST *view)
{
TABLE *table;
- Field_translator *trans;
+ Field_translator *trans, *end_of_trans;
KEY *key_info, *key_info_end;
- uint i, elements_in_view;
+ uint i;
DBUG_ENTER("check_key_in_view");
/*
@@ -1010,9 +1095,24 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
trans= view->field_translation;
key_info_end= (key_info= table->key_info)+ table->s->keys;
- elements_in_view= view->view->select_lex.item_list.elements;
+ end_of_trans= view->field_translation_end;
DBUG_ASSERT(table != 0 && view->field_translation != 0);
+ {
+ /*
+ We should be sure that all fields are ready to get keys from them, but
+ this operation should not have influence on Field::query_id, to avoid
+ marking as used fields which are not used
+ */
+ bool save_set_query_id= thd->set_query_id;
+ thd->set_query_id= 0;
+ for (Field_translator *fld= trans; fld < end_of_trans; fld++)
+ {
+ if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item))
+ return TRUE;
+ }
+ thd->set_query_id= save_set_query_id;
+ }
/* Loop over all keys to see if a unique-not-null key is used */
for (;key_info != key_info_end ; key_info++)
{
@@ -1024,15 +1124,15 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
/* check that all key parts are used */
for (;;)
{
- uint k;
- for (k= 0; k < elements_in_view; k++)
+ Field_translator *k;
+ for (k= trans; k < end_of_trans; k++)
{
Item_field *field;
- if ((field= trans[k].item->filed_for_view_update()) &&
+ if ((field= k->item->filed_for_view_update()) &&
field->field == key_part->field)
break;
}
- if (k == elements_in_view)
+ if (k == end_of_trans)
break; // Key is not possible
if (++key_part == key_part_end)
DBUG_RETURN(FALSE); // Found usable key
@@ -1044,19 +1144,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
/* check all fields presence */
{
Field **field_ptr;
+ Field_translator *fld;
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
- for (i= 0; i < elements_in_view; i++)
+ for (fld= trans; fld < end_of_trans; fld++)
{
Item_field *field;
- if ((field= trans[i].item->filed_for_view_update()) &&
+ if ((field= fld->item->filed_for_view_update()) &&
field->field == *field_ptr)
break;
}
- if (i == elements_in_view) // If field didn't exists
+ if (fld == end_of_trans) // If field didn't exists
{
/*
- Keys or all fields of underlying tables are not foud => we have
+ Keys or all fields of underlying tables are not found => we have
to check variable updatable_views_with_limit to decide should we
issue an error or just a warning
*/
@@ -1081,6 +1182,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
SYNOPSIS
insert_view_fields()
+ thd thread handler
list list for insertion
view view for processing
@@ -1089,19 +1191,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
TRUE error (is not sent to cliet)
*/
-bool insert_view_fields(List<Item> *list, TABLE_LIST *view)
+bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view)
{
- uint elements_in_view= view->view->select_lex.item_list.elements;
+ Field_translator *trans_end;
Field_translator *trans;
DBUG_ENTER("insert_view_fields");
if (!(trans= view->field_translation))
DBUG_RETURN(FALSE);
+ trans_end= view->field_translation_end;
- for (uint i= 0; i < elements_in_view; i++)
+ for (Field_translator *entry= trans; entry < trans_end; entry++)
{
Item_field *fld;
- if ((fld= trans[i].item->filed_for_view_update()))
+ if ((fld= entry->item->filed_for_view_update()))
list->push_back(fld);
else
{
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 4e6aaf7f477..3246dbae383 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
bool check_key_in_view(THD *thd, TABLE_LIST * view);
-bool insert_view_fields(List<Item> *list, TABLE_LIST *view);
+bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view);
frm_type_enum mysql_frm_type(char *path);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 570a277938a..2397540deae 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -465,6 +465,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PACK_KEYS_SYM
%token PARTIAL
%token PASSWORD
+%token PARAM_MARKER
%token PHASE_SYM
%token POINTFROMTEXT
%token POINT_SYM
@@ -676,7 +677,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
- sp_opt_label BIN_NUM
+ sp_opt_label BIN_NUM label_ident
%type <lex_str_ptr>
opt_table_alias
@@ -764,7 +765,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <udf_type> udf_func_type
-%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword
+%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp
%type <lex_user> user grant_user
@@ -914,7 +915,7 @@ deallocate:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
@@ -939,7 +940,7 @@ prepare:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
@@ -974,7 +975,7 @@ execute:
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ if (thd->command == COM_STMT_PREPARE)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
@@ -1259,7 +1260,6 @@ create:
THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
/* first table in list is target VIEW name */
if (!lex->select_lex.add_table_to_list(thd, $5, NULL, 0))
YYABORT;
@@ -1532,7 +1532,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
- sp_add_to_hash(&lex->spprocs, $2);
+ sp_add_used_routine(lex, YYTHD, $2, TYPE_ENUM_PROCEDURE);
}
'(' sp_cparam_list ')' {}
;
@@ -2054,7 +2054,7 @@ sp_proc_stmt:
lex->sphead->backpatch(lex->spcont->pop_label());
}
- | LEAVE_SYM IDENT
+ | LEAVE_SYM label_ident
{
LEX *lex= Lex;
sp_head *sp = lex->sphead;
@@ -2084,7 +2084,7 @@ sp_proc_stmt:
sp->add_instr(i);
}
}
- | ITERATE_SYM IDENT
+ | ITERATE_SYM label_ident
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -2114,6 +2114,7 @@ sp_proc_stmt:
}
| LABEL_SYM IDENT
{
+#ifdef SP_GOTO
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
@@ -2131,9 +2132,14 @@ sp_proc_stmt:
lab->ctx= ctx;
sp->backpatch(lab);
}
+#else
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+#endif
}
| GOTO_SYM IDENT
{
+#ifdef SP_GOTO
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
@@ -2186,6 +2192,10 @@ sp_proc_stmt:
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
sp->add_instr(i);
}
+#else
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+#endif
}
| OPEN_SYM ident
{
@@ -2391,7 +2401,7 @@ sp_whens:
;
sp_labeled_control:
- IDENT ':'
+ label_ident ':'
{
LEX *lex= Lex;
sp_pcontext *ctx= lex->spcont;
@@ -2430,7 +2440,7 @@ sp_labeled_control:
sp_opt_label:
/* Empty */ { $$= null_lex_str; }
- | IDENT { $$= $1; }
+ | label_ident { $$= $1; }
;
sp_unlabeled_control:
@@ -3383,7 +3393,6 @@ alter:
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
lex->create_view_mode= VIEW_ALTER;
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
/* first table in list is target VIEW name */
lex->select_lex.add_table_to_list(thd, $4, NULL, 0);
}
@@ -3941,7 +3950,6 @@ select:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
}
;
@@ -4095,7 +4103,10 @@ select_item_list:
| '*'
{
THD *thd= YYTHD;
- if (add_item_to_list(thd, new Item_field(NULL, NULL, "*")))
+ if (add_item_to_list(thd,
+ new Item_field(&thd->lex->current_select->
+ context,
+ NULL, NULL, "*")))
YYABORT;
(thd->lex->current_select->with_wild)++;
};
@@ -4107,7 +4118,10 @@ select_item:
if (add_item_to_list(YYTHD, $2))
YYABORT;
if ($4.str)
- $2->set_name($4.str,$4.length,system_charset_info);
+ {
+ $2->set_name($4.str, $4.length, system_charset_info);
+ $2->is_autogenerated_name= FALSE;
+ }
else if (!$2->name) {
char *str = $1;
if (str[-1] == '`')
@@ -4390,10 +4404,10 @@ simple_expr:
my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
YYABORT;
}
- $$= new Item_default_value($3);
+ $$= new Item_default_value(&Select->context, $3);
}
| VALUES '(' simple_ident ')'
- { $$= new Item_insert_value($3); }
+ { $$= new Item_insert_value(&Select->context, $3); }
| FUNC_ARG0 '(' ')'
{
if (!$1.symbol->create_func)
@@ -4682,17 +4696,18 @@ simple_expr:
sp_name *name= new sp_name($1, $3);
name->init_qname(YYTHD);
- sp_add_to_hash(&lex->spfuns, name);
+ sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
if ($5)
- $$= new Item_func_sp(name, *$5);
+ $$= new Item_func_sp(&lex->current_select->context, name, *$5);
else
- $$= new Item_func_sp(name);
+ $$= new Item_func_sp(&lex->current_select->context, name);
lex->safe_to_cache_query=0;
}
| IDENT_sys '(' udf_expr_list ')'
{
#ifdef HAVE_DLOPEN
udf_func *udf;
+ SELECT_LEX *sel= Select;
if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
{
@@ -4771,11 +4786,11 @@ simple_expr:
LEX *lex= Lex;
sp_name *name= sp_name_current_db_new(YYTHD, $1);
- sp_add_to_hash(&lex->spfuns, name);
+ sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
if ($3)
- $$= new Item_func_sp(name, *$3);
+ $$= new Item_func_sp(&lex->current_select->context, name, *$3);
else
- $$= new Item_func_sp(name);
+ $$= new Item_func_sp(&lex->current_select->context, name);
lex->safe_to_cache_query=0;
}
}
@@ -4791,7 +4806,7 @@ simple_expr:
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
+ { $$= new Item_func_user(FALSE); Lex->safe_to_cache_query=0; }
| UTC_DATE_SYM optional_braces
{ $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
| UTC_TIME_SYM optional_braces
@@ -4913,9 +4928,12 @@ udf_expr:
remember_name expr remember_end select_alias
{
if ($4.str)
- $2->set_name($4.str,$4.length,system_charset_info);
+ {
+ $2->set_name($4.str, $4.length, system_charset_info);
+ $2->is_autogenerated_name= FALSE;
+ }
else
- $2->set_name($1,(uint) ($3 - $1), YYTHD->charset());
+ $2->set_name($1, (uint) ($3 - $1), YYTHD->charset());
$$= $2;
}
;
@@ -4974,8 +4992,10 @@ sum_expr:
opt_gconcat_separator
')'
{
- Select->in_sum_expr--;
- $$=new Item_func_group_concat($3,$5,Select->gorder_list,$7);
+ SELECT_LEX *sel= Select;
+ sel->in_sum_expr--;
+ $$=new Item_func_group_concat(&sel->context, $3, $5,
+ sel->gorder_list, $7);
$5->empty();
};
@@ -5394,16 +5414,30 @@ using_list:
ident
{
SELECT_LEX *sel= Select;
- if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1,
+ if (!($$= new Item_func_eq(new Item_field(&sel->context,
+ sel->db1, sel->table1,
$1.str),
- new Item_field(sel->db2, sel->table2,
+ new Item_field(&sel->context,
+ sel->db2, sel->table2,
$1.str))))
YYABORT;
}
| using_list ',' ident
{
SELECT_LEX *sel= Select;
- if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1)))
+ 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;
};
@@ -5641,7 +5675,7 @@ delete_limit_clause:
ulong_num:
NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | HEX_NUM { int error; $$= (ulong) strtol($1.str, (char**) 0, 16); }
+ | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
| LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
@@ -5669,7 +5703,10 @@ procedure_clause:
lex->proc_list.elements=0;
lex->proc_list.first=0;
lex->proc_list.next= (byte**) &lex->proc_list.first;
- if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str)))
+ if (add_proc_to_list(lex->thd, new Item_field(&lex->
+ current_select->
+ context,
+ NULL,NULL,$2.str)))
YYABORT;
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
}
@@ -5691,7 +5728,8 @@ procedure_item:
if (add_proc_to_list(lex->thd, $2))
YYABORT;
if (!$2->name)
- $2->set_name($1,(uint) ((char*) lex->tok_end - $1), YYTHD->charset());
+ $2->set_name($1,(uint) ((char*) lex->tok_end - $1),
+ YYTHD->charset());
}
;
@@ -5915,7 +5953,6 @@ insert:
mysql_init_select(lex);
/* for subselects */
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
} insert_lock_option
opt_ignore insert2
{
@@ -5933,7 +5970,6 @@ replace:
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
mysql_init_select(lex);
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
}
replace_lock_option insert2
{
@@ -6051,7 +6087,7 @@ values:
expr_or_default:
expr { $$= $1;}
- | DEFAULT {$$= new Item_default_value(); }
+ | DEFAULT {$$= new Item_default_value(&Select->context); }
;
opt_insert_update:
@@ -6898,23 +6934,15 @@ text_string:
;
param_marker:
- '?'
+ PARAM_MARKER
{
THD *thd=YYTHD;
LEX *lex= thd->lex;
- if (thd->command == COM_PREPARE)
+ Item_param *item= new Item_param((uint) (lex->tok_start -
+ (uchar *) thd->query));
+ if (!($$= item) || lex->param_list.push_back(item))
{
- Item_param *item= new Item_param((uint) (lex->tok_start -
- (uchar *) thd->query));
- if (!($$= item) || lex->param_list.push_back(item))
- {
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- YYABORT;
- }
- }
- else
- {
- yyerror(ER(ER_SYNTAX_ERROR));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
YYABORT;
}
}
@@ -7005,15 +7033,17 @@ insert_ident:
table_wild:
ident '.' '*'
{
- $$ = new Item_field(NullS,$1.str,"*");
- Lex->current_select->with_wild++;
+ SELECT_LEX *sel= Select;
+ $$ = new Item_field(&sel->context, NullS, $1.str, "*");
+ sel->with_wild++;
}
| ident '.' ident '.' '*'
{
- $$ = new Item_field((YYTHD->client_capabilities &
+ SELECT_LEX *sel= Select;
+ $$ = new Item_field(&sel->context, (YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str,"*");
- Lex->current_select->with_wild++;
+ sel->with_wild++;
}
;
@@ -7038,8 +7068,8 @@ simple_ident:
SELECT_LEX *sel=Select;
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,NullS,$1.str) :
- (Item*) new Item_ref(NullS,NullS,$1.str);
+ (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) :
+ (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str);
}
}
| simple_ident_q { $$= $1; }
@@ -7051,8 +7081,8 @@ simple_ident_nospvar:
SELECT_LEX *sel=Select;
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,NullS,$1.str) :
- (Item*) new Item_ref(NullS,NullS,$1.str);
+ (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) :
+ (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str);
}
| simple_ident_q { $$= $1; }
;
@@ -7089,7 +7119,8 @@ simple_ident_q:
YYABORT;
}
- if (!(trg_fld= new Item_trigger_field(new_row ?
+ if (!(trg_fld= new Item_trigger_field(&lex->current_select->context,
+ new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
$3.str)))
@@ -7114,8 +7145,8 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,$1.str,$3.str) :
- (Item*) new Item_ref(NullS,$1.str,$3.str);
+ (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) :
+ (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str);
}
}
| '.' ident '.' ident
@@ -7130,8 +7161,8 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,$2.str,$4.str) :
- (Item*) new Item_ref(NullS, $2.str, $4.str);
+ (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) :
+ (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str);
}
| ident '.' ident '.' ident
{
@@ -7145,10 +7176,12 @@ simple_ident_q:
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field((YYTHD->client_capabilities &
+ (Item*) new Item_field(&sel->context,
+ (YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str, $5.str) :
- (Item*) new Item_ref((YYTHD->client_capabilities &
+ (Item*) new Item_ref(&sel->context,
+ (YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str, $5.str);
};
@@ -7255,6 +7288,16 @@ ident:
}
;
+label_ident:
+ IDENT_sys { $$=$1; }
+ | keyword_sp
+ {
+ THD *thd= YYTHD;
+ $$.str= thd->strmake($1.str, $1.length);
+ $$.length= $1.length;
+ }
+ ;
+
ident_or_text:
ident { $$=$1;}
| TEXT_STRING_sys { $$=$1;}
@@ -7296,9 +7339,53 @@ user:
}
};
-/* Keyword that we allow for identifiers */
-
+/* Keyword that we allow for identifiers (except SP labels) */
keyword:
+ keyword_sp {}
+ | ASCII_SYM {}
+ | BACKUP_SYM {}
+ | BEGIN_SYM {}
+ | BYTE_SYM {}
+ | CACHE_SYM {}
+ | CHARSET {}
+ | CHECKSUM_SYM {}
+ | CLOSE_SYM {}
+ | COMMENT_SYM {}
+ | COMMIT_SYM {}
+ | CONTAINS_SYM {}
+ | DEALLOCATE_SYM {}
+ | DO_SYM {}
+ | END {}
+ | EXECUTE_SYM {}
+ | FLUSH_SYM {}
+ | HANDLER_SYM {}
+ | HELP_SYM {}
+ | LANGUAGE_SYM {}
+ | NO_SYM {}
+ | OPEN_SYM {}
+ | PREPARE_SYM {}
+ | REPAIR {}
+ | RESET_SYM {}
+ | RESTORE_SYM {}
+ | ROLLBACK_SYM {}
+ | SAVEPOINT_SYM {}
+ | SECURITY_SYM {}
+ | SIGNED_SYM {}
+ | SLAVE {}
+ | START_SYM {}
+ | STOP_SYM {}
+ | TRUNCATE_SYM {}
+ | UNICODE_SYM {}
+ | XA_SYM {}
+ ;
+
+/*
+ * Keywords that we allow for labels in SPs.
+ * Anything that's the beginning of a statement or characteristics
+ * must be in keyword above, otherwise we get (harmful) shift/reduce
+ * conflicts.
+ */
+keyword_sp:
ACTION {}
| ADDDATE_SYM {}
| AFTER_SYM {}
@@ -7306,61 +7393,46 @@ keyword:
| AGGREGATE_SYM {}
| ALGORITHM_SYM {}
| ANY_SYM {}
- | ASCII_SYM {}
| AUTO_INC {}
| AVG_ROW_LENGTH {}
| AVG_SYM {}
- | BACKUP_SYM {}
- | BEGIN_SYM {}
| BERKELEY_DB_SYM {}
| BINLOG_SYM {}
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
- | BYTE_SYM {}
| BTREE_SYM {}
- | CACHE_SYM {}
| CASCADED {}
| CHAIN_SYM {}
| CHANGED {}
- | CHARSET {}
- | CHECKSUM_SYM {}
| CIPHER_SYM {}
| CLIENT_SYM {}
- | CLOSE_SYM {}
| COLLATION_SYM {}
| COLUMNS {}
- | COMMENT_SYM {}
| COMMITTED_SYM {}
- | COMMIT_SYM {}
| COMPACT_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
| CONSISTENT_SYM {}
- | CONTAINS_SYM {}
| CUBE_SYM {}
| DATA_SYM {}
| DATETIME {}
| DATE_SYM {}
| DAY_SYM {}
- | DEALLOCATE_SYM {}
| DEFINER_SYM {}
| DELAY_KEY_WRITE_SYM {}
| DES_KEY_FILE {}
| DIRECTORY_SYM {}
| DISCARD {}
- | DO_SYM {}
| DUMPFILE {}
| DUPLICATE_SYM {}
| DYNAMIC_SYM {}
- | END {}
| ENUM {}
| ENGINE_SYM {}
| ENGINES_SYM {}
| ERRORS {}
| ESCAPE_SYM {}
| EVENTS_SYM {}
- | EXECUTE_SYM {}
| EXPANSION_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
@@ -7371,16 +7443,13 @@ keyword:
| FILE_SYM {}
| FIRST_SYM {}
| FIXED_SYM {}
- | FLUSH_SYM {}
| FRAC_SECOND_SYM {}
| GEOMETRY_SYM {}
| GEOMETRYCOLLECTION {}
| GET_FORMAT {}
| GRANTS {}
| GLOBAL_SYM {}
- | HANDLER_SYM {}
| HASH_SYM {}
- | HELP_SYM {}
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
@@ -7392,8 +7461,6 @@ keyword:
| INNOBASE_SYM {}
| INSERT_METHOD {}
| RELAY_THREAD {}
- | LABEL_SYM {}
- | LANGUAGE_SYM {}
| LAST_SYM {}
| LEAVES {}
| LEVEL_SYM {}
@@ -7441,21 +7508,18 @@ keyword:
| NDBCLUSTER_SYM {}
| NEXT_SYM {}
| NEW_SYM {}
- | NO_SYM {}
| NONE_SYM {}
| NVARCHAR_SYM {}
| OFFSET_SYM {}
| OLD_PASSWORD {}
| ONE_SHOT_SYM {}
| ONE_SYM {}
- | OPEN_SYM {}
| PACK_KEYS_SYM {}
| PARTIAL {}
| PASSWORD {}
| PHASE_SYM {}
| POINT_SYM {}
| POLYGON {}
- | PREPARE_SYM {}
| PREV_SYM {}
| PRIVILEGES {}
| PROCESS {}
@@ -7473,41 +7537,31 @@ keyword:
| RELAY_LOG_FILE_SYM {}
| RELAY_LOG_POS_SYM {}
| RELOAD {}
- | REPAIR {}
| REPEATABLE_SYM {}
| REPLICATION {}
- | RESET_SYM {}
| RESOURCES {}
- | RESTORE_SYM {}
| RESUME_SYM {}
| RETURNS_SYM {}
- | ROLLBACK_SYM {}
| ROLLUP_SYM {}
| ROUTINE_SYM {}
| ROWS_SYM {}
| ROW_FORMAT_SYM {}
| ROW_SYM {}
| RTREE_SYM {}
- | SAVEPOINT_SYM {}
| SECOND_SYM {}
- | SECURITY_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}
| SESSION_SYM {}
- | SIGNED_SYM {}
| SIMPLE_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
- | SLAVE {}
| SNAPSHOT_SYM {}
| SOUNDS_SYM {}
| SQL_CACHE_SYM {}
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
| SQL_THREAD {}
- | START_SYM {}
| STATUS_SYM {}
- | STOP_SYM {}
| STORAGE_SYM {}
| STRING_SYM {}
| SUBDATE_SYM {}
@@ -7520,7 +7574,6 @@ keyword:
| TEMPTABLE_SYM {}
| TEXT_SYM {}
| TRANSACTION_SYM {}
- | TRUNCATE_SYM {}
| TIMESTAMP {}
| TIMESTAMP_ADD {}
| TIMESTAMP_DIFF {}
@@ -7531,7 +7584,6 @@ keyword:
| FUNCTION_SYM {}
| UNCOMMITTED_SYM {}
| UNDEFINED_SYM {}
- | UNICODE_SYM {}
| UNKNOWN_SYM {}
| UNTIL_SYM {}
| USER {}
@@ -7543,7 +7595,6 @@ keyword:
| WEEK_SYM {}
| WORK_SYM {}
| X509_SYM {}
- | XA_SYM {}
| YEAR_SYM {}
;
@@ -7684,12 +7735,6 @@ sys_option_value:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
- if (lex->query_tables)
- {
- my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
- MYF(0));
- YYABORT;
- }
if ($4)
it= $4;
else
@@ -7698,11 +7743,14 @@ sys_option_value:
it= new Item_null();
}
- if (!(trg_fld= new Item_trigger_field(Item_trigger_field::NEW_ROW,
+ if (!(trg_fld= new Item_trigger_field(&lex->current_select->
+ 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)))
+ !(i= new sp_instr_set_trigger_field(lex->sphead->
+ instructions(),
+ lex->spcont, trg_fld,
+ it, lex)))
YYABORT;
/*
diff --git a/sql/table.cc b/sql/table.cc
index 55beac10812..220aba27d5b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -163,7 +163,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5)
share->frm_version= FRM_VER_TRUE_VARCHAR;
- share->db_type= ha_checktype((enum db_type) (uint) *(head+3));
+ share->db_type= ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0);
share->db_create_options= db_create_options=uint2korr(head+30);
share->db_options_in_use= share->db_create_options;
share->mysql_version= uint4korr(head+51);
@@ -594,6 +594,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err; /* purecov: inspected */
}
+ reg_field->field_index= i;
reg_field->comment=comment;
if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
{
@@ -745,8 +746,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
error.
*/
keyinfo->key_length-= (key_part->length - field->key_length());
- key_part->store_length-= (key_part->length - field->key_length());
- key_part->length= field->key_length();
+ key_part->store_length-= (uint16)(key_part->length -
+ field->key_length());
+ key_part->length= (uint16)field->key_length();
sql_print_error("Found wrong key definition in %s; Please do \"ALTER TABLE '%s' FORCE \" to fix it!", name, share->table_name);
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_CRASHED_ON_USAGE,
@@ -1341,8 +1343,8 @@ void append_unescaped(String *res, const char *pos, uint length)
/* Create a .frm file */
-File create_frm(register my_string name, uint reclength, uchar *fileinfo,
- HA_CREATE_INFO *create_info, uint keys)
+File create_frm(THD *thd, register my_string name, uint reclength,
+ uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys)
{
register File file;
ulong length;
@@ -1375,7 +1377,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
fileinfo[1]= 1;
fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
- fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
+ fileinfo[3]= (uchar) ha_checktype(thd,create_info->db_type,0,0);
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
@@ -1637,7 +1639,7 @@ bool check_column_name(const char *name)
** Get type of table from .frm file
*/
-db_type get_table_type(const char *name)
+db_type get_table_type(THD *thd, const char *name)
{
File file;
uchar head[4];
@@ -1653,7 +1655,7 @@ db_type get_table_type(const char *name)
(head[2] != FRM_VER && head[2] != FRM_VER+1 &&
(head[2] < FRM_VER+3 || head[2] > FRM_VER+4)))
DBUG_RETURN(DB_TYPE_UNKNOWN);
- DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
+ DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0));
}
@@ -1713,8 +1715,6 @@ void st_table_list::set_ancestor()
}
if (tbl->multitable_view)
multitable_view= TRUE;
- if (tbl->table)
- tbl->table->grant= grant;
} while ((tbl= tbl->next_local));
if (!multitable_view)
@@ -1727,68 +1727,18 @@ void st_table_list::set_ancestor()
/*
- Save old want_privilege and clear want_privilege
-
- SYNOPSIS
- save_and_clear_want_privilege()
-*/
-
-void st_table_list::save_and_clear_want_privilege()
-{
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
- {
- if (tbl->table)
- {
- privilege_backup= tbl->table->grant.want_privilege;
- tbl->table->grant.want_privilege= 0;
- }
- else
- {
- tbl->save_and_clear_want_privilege();
- }
- }
-}
-
-
-/*
- restore want_privilege saved by save_and_clear_want_privilege
-
- SYNOPSIS
- restore_want_privilege()
-*/
-
-void st_table_list::restore_want_privilege()
-{
- for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
- {
- if (tbl->table)
- tbl->table->grant.want_privilege= privilege_backup;
- else
- {
- tbl->restore_want_privilege();
- }
- }
-}
-
-
-/*
setup fields of placeholder of merged VIEW
SYNOPSIS
st_table_list::setup_ancestor()
thd - thread handler
- conds - condition of this JOIN
- check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE,
- VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
+
NOTES
ancestor is list of tables and views used by view (underlying tables/views)
DESCRIPTION
It is:
- - preparing translation table for view columns (fix_fields() for every
- call and creation for first call)
- - preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every
- call and merging for first call).
+ - preparing translation table for view columns
If there are underlying view(s) procedure first will be called for them.
RETURN
@@ -1796,163 +1746,114 @@ void st_table_list::restore_want_privilege()
TRUE - error
*/
-bool st_table_list::setup_ancestor(THD *thd, Item **conds,
- uint8 check_opt_type)
+bool st_table_list::setup_ancestor(THD *thd)
{
- Field_translator *transl;
- SELECT_LEX *select= &view->select_lex;
- SELECT_LEX *current_select_save= thd->lex->current_select;
- byte *main_table_list_save= select_lex->table_list.first;
- Item *item;
- TABLE_LIST *tbl;
- List_iterator_fast<Item> it(select->item_list);
- uint i= 0;
- enum sub_select_type linkage_save=
- select_lex->master_unit()->first_select()->linkage;
- bool save_set_query_id= thd->set_query_id;
- bool save_wrapper= select_lex->no_wrap_view_item;
- bool save_allow_sum_func= thd->allow_sum_func;
- bool res= FALSE;
DBUG_ENTER("st_table_list::setup_ancestor");
-
- if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res))
- return TRUE;
-
- for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ if (!field_translation)
{
- if (tbl->ancestor &&
- tbl->setup_ancestor(thd, conds,
- (check_opt_type == VIEW_CHECK_CASCADED ?
- VIEW_CHECK_CASCADED :
- VIEW_CHECK_NONE)))
+ Field_translator *transl;
+ SELECT_LEX *select= &view->select_lex;
+ Item *item;
+ TABLE_LIST *tbl;
+ List_iterator_fast<Item> it(select->item_list);
+ uint field_count= 0;
+
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&field_count))
+ {
DBUG_RETURN(TRUE);
- }
+ }
- /*
- We have to ensure that inside the view we are not referring to any
- table outside of the view. We do it by changing the pointers used
- by fix_fields to look up tables so that only tables and views in
- view are seen. We also set linkage to DERIVED_TABLE_TYPE as a barrier
- so that we stop resolving fields as this level.
- */
- thd->lex->current_select= select_lex;
- select_lex->table_list.first= (byte *)ancestor;
- select_lex->master_unit()->first_select()->linkage= DERIVED_TABLE_TYPE;
+ for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->ancestor &&
+ tbl->setup_ancestor(thd))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
- if (field_translation)
- {
- DBUG_PRINT("info", ("there are already translation table"));
-
- select_lex->no_wrap_view_item= 1;
-
- thd->set_query_id= 1;
- /* this view was prepared already on previous PS/SP execution */
- Field_translator *end= field_translation + select->item_list.elements;
- /* real rights will be checked in VIEW field */
- save_and_clear_want_privilege();
- /* aggregate function are allowed */
- thd->allow_sum_func= 1;
- for (transl= field_translation; transl < end; transl++)
+ /* Create view fields translation table */
+
+ if (!(transl=
+ (Field_translator*)(thd->current_arena->
+ alloc(select->item_list.elements *
+ sizeof(Field_translator)))))
{
- if (!transl->item->fixed &&
- transl->item->fix_fields(thd, ancestor, &transl->item))
- goto err;
+ DBUG_RETURN(TRUE);
}
- for (tbl= ancestor; tbl; tbl= tbl->next_local)
+
+ while ((item= it++))
{
- if (tbl->on_expr && !tbl->on_expr->fixed &&
- tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
- goto err;
+ transl[field_count].name= item->name;
+ transl[field_count++].item= item;
}
- if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
- goto err;
- if (check_option && !check_option->fixed &&
- check_option->fix_fields(thd, ancestor, &check_option))
- goto err;
- restore_want_privilege();
+ field_translation= transl;
+ field_translation_end= transl + field_count;
+ /* TODO: use hash for big number of fields */
- /* WHERE/ON resolved => we can rename fields */
- for (transl= field_translation; transl < end; transl++)
+ /* full text function moving to current select */
+ if (view->select_lex.ftfunc_list->elements)
{
- transl->item->rename((char *)transl->name);
+ Item_func_match *ifm;
+ SELECT_LEX *current_select= thd->lex->current_select;
+ List_iterator_fast<Item_func_match>
+ li(*(view->select_lex.ftfunc_list));
+ while ((ifm= li++))
+ current_select->ftfunc_list->push_front(ifm);
}
- goto ok;
}
+ DBUG_RETURN(FALSE);
+}
- /* Create view fields translation table */
- if (!(transl=
- (Field_translator*)(thd->current_arena->
- alloc(select->item_list.elements *
- sizeof(Field_translator)))))
- {
- res= TRUE;
- goto ok; // Restore thd
- }
+/*
+ Prepare where expression of view
- select_lex->no_wrap_view_item= 1;
+ SYNOPSIS
+ st_table_list::prep_where()
+ thd - thread handler
+ conds - condition of this JOIN
+ no_where_clause - do not build WHERE or ON outer qwery do not need it
+ (it is INSERT), we do not need conds if this flag is set
- /*
- Resolve all view items against ancestor table.
+ NOTE: have to be called befor CHECK OPTION preparation, because it makes
+ fix_fields for view WHERE clause
- TODO: do it only for real used fields "on demand" to mark really
- used fields correctly.
- */
- thd->set_query_id= 1;
- /* real rights will be checked in VIEW field */
- save_and_clear_want_privilege();
- /* aggregate function are allowed */
- thd->allow_sum_func= 1;
- while ((item= it++))
- {
- /* save original name of view column */
- char *name= item->name;
- transl[i].item= item;
- if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item))
- goto err;
- /* set new item get in fix fields and original column name */
- transl[i++].name= name;
- }
- field_translation= transl;
- /* TODO: sort this list? Use hash for big number of fields */
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
- for (tbl= ancestor; tbl; tbl= tbl->next_local)
+bool st_table_list::prep_where(THD *thd, Item **conds,
+ bool no_where_clause)
+{
+ DBUG_ENTER("st_table_list::prep_where");
+
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
- if (tbl->on_expr && !tbl->on_expr->fixed &&
- tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
- goto err;
+ if (tbl->view && tbl->prep_where(thd, conds, no_where_clause))
+ {
+ DBUG_RETURN(TRUE);
+ }
}
- if (where ||
- (check_opt_type == VIEW_CHECK_CASCADED &&
- ancestor->check_option))
- {
- Query_arena *arena= thd->current_arena, backup;
- TABLE_LIST *tbl= this;
- if (arena->is_conventional())
- arena= 0; // For easier test
-
- if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
- goto err;
-
- if (arena)
- thd->set_n_backup_item_arena(arena, &backup);
- if (check_opt_type)
+ if (where)
+ {
+ if (!where->fixed && where->fix_fields(thd, &where))
{
- if (where)
- check_option= where->copy_andor_structure(thd);
- if (check_opt_type == VIEW_CHECK_CASCADED)
- {
- check_option= and_conds(check_option, ancestor->check_option);
- }
+ DBUG_RETURN(TRUE);
}
/*
check that it is not VIEW in which we insert with INSERT SELECT
(in this case we can't add view WHERE condition to main SELECT_LEX)
*/
- if (where && !no_where_clause)
+ if (!no_where_clause && !where_processed)
{
+ TABLE_LIST *tbl= this;
+ Query_arena *arena= thd->current_arena, backup;
+ arena= thd->change_arena_if_needed(&backup); // For easier test
+
/* Go up to join tree and try to find left join */
for (; tbl; tbl= tbl->embedding)
{
@@ -1969,72 +1870,107 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
}
}
if (tbl == 0)
- {
- if (outer_join)
- {
- /*
- Store WHERE condition to ON expression for outer join, because
- we can't use WHERE to correctly execute left joins on VIEWs and
- this expression will not be moved to WHERE condition (i.e. will
- be clean correctly for PS/SP)
- */
- on_expr= and_conds(on_expr, where);
- }
- else
- {
- /*
- It is conds of JOIN, but it will be stored in
- st_select_lex::prep_where for next reexecution
- */
- *conds= and_conds(*conds, where);
- }
- }
+ *conds= and_conds(*conds, where);
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ where_processed= TRUE;
}
-
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
}
- restore_want_privilege();
- /*
- fix_fields do not need tables, because new are only AND operation and we
- just need recollect statistics
- */
- if (check_option && !check_option->fixed &&
- check_option->fix_fields(thd, 0, &check_option))
- goto err;
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Prepare check option expression of table
+
+ SYNOPSIS
+ st_table_list::prep_check_option()
+ thd - thread handler
+ check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE,
+ VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
+ we use this parameter instead of direct check of
+ effective_with_check to change type of underlying
+ views to VIEW_CHECK_CASCADED if outer view have
+ such option and prevent processing of underlying
+ view check options if outer view have just
+ VIEW_CHECK_LOCAL option.
+
+ NOTE
+ This method build check options for every call
+ (usual execution or every SP/PS call)
+ This method have to be called after WHERE preparation
+ (st_table_list::prep_where)
- /* WHERE/ON resolved => we can rename fields */
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
+{
+ DBUG_ENTER("st_table_list::prep_check_option");
+
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
- Field_translator *end= field_translation + select->item_list.elements;
- for (transl= field_translation; transl < end; transl++)
+ /* see comment of check_opt_type parameter */
+ if (tbl->view &&
+ tbl->prep_check_option(thd,
+ ((check_opt_type == VIEW_CHECK_CASCADED) ?
+ VIEW_CHECK_CASCADED :
+ VIEW_CHECK_NONE)))
{
- transl->item->rename((char *)transl->name);
+ DBUG_RETURN(TRUE);
}
}
- /* full text function moving to current select */
- if (view->select_lex.ftfunc_list->elements)
+ if (check_opt_type)
{
- Query_arena *arena= thd->current_arena, backup;
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_item_arena(arena, &backup);
-
- Item_func_match *ifm;
- List_iterator_fast<Item_func_match>
- li(*(view->select_lex.ftfunc_list));
- while ((ifm= li++))
- current_select_save->ftfunc_list->push_front(ifm);
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
+ Item *item= 0;
+ if (where)
+ {
+ DBUG_ASSERT(where->fixed);
+ item= where->copy_andor_structure(thd);
+ }
+ if (check_opt_type == VIEW_CHECK_CASCADED)
+ {
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->check_option)
+ item= and_conds(item, tbl->check_option);
+ }
+ }
+ if (item)
+ thd->change_item_tree(&check_option, item);
+ }
+
+ if (check_option)
+ {
+ const char *save_where= thd->where;
+ thd->where= "check option";
+ if (!check_option->fixed &&
+ check_option->fix_fields(thd, &check_option) ||
+ check_option->check_cols(1))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ thd->where= save_where;
}
+ DBUG_RETURN(FALSE);
+}
+
- goto ok;
+/*
+ Hide errors which show view underlying table information
+
+ SYNOPSIS
+ st_table_list::hide_view_error()
+ thd thread handler
-err:
- res= TRUE;
+*/
+
+void st_table_list::hide_view_error(THD *thd)
+{
/* Hide "Unknown column" or "Unknown function" error */
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
@@ -2042,15 +1978,12 @@ err:
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
}
-
-ok:
- select_lex->no_wrap_view_item= save_wrapper;
- thd->lex->current_select= current_select_save;
- select_lex->table_list.first= main_table_list_save;
- select_lex->master_unit()->first_select()->linkage= linkage_save;
- thd->set_query_id= save_set_query_id;
- thd->allow_sum_func= save_allow_sum_func;
- DBUG_RETURN(res);
+ else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
+ {
+ thd->clear_error();
+ // TODO: make correct error message
+ my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str);
+ }
}
@@ -2094,9 +2027,9 @@ void st_table_list::cleanup_items()
if (!field_translation)
return;
- Field_translator *end= (field_translation +
- view->select_lex.item_list.elements);
- for (Field_translator *transl= field_translation; transl < end; transl++)
+ for (Field_translator *transl= field_translation;
+ transl < field_translation_end;
+ transl++)
transl->item->walk(&Item::cleanup_processor, 0);
}
@@ -2209,8 +2142,9 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
void Field_iterator_view::set(TABLE_LIST *table)
{
+ view= table;
ptr= table->field_translation;
- array_end= ptr + table->view->select_lex.item_list.elements;
+ array_end= table->field_translation_end;
}
@@ -2220,9 +2154,9 @@ const char *Field_iterator_table::name()
}
-Item *Field_iterator_table::item(THD *thd)
+Item *Field_iterator_table::create_item(THD *thd)
{
- return new Item_field(thd, *ptr);
+ return new Item_field(thd, &thd->lex->current_select->context, *ptr);
}
@@ -2232,11 +2166,56 @@ const char *Field_iterator_view::name()
}
+Item *Field_iterator_view::create_item(THD *thd)
+{
+ return create_view_field(thd, view, &ptr->item, ptr->name);
+}
+
+Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
+ const char *name)
+{
+ bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
+ Item *field= *field_ref;
+ DBUG_ENTER("create_view_field");
+
+ if (view->schema_table_reformed)
+ {
+ /*
+ In case of SHOW command (schema_table_reformed set) all items are
+ fixed
+ */
+ DBUG_ASSERT(field && field->fixed);
+ DBUG_RETURN(field);
+ }
+
+ DBUG_ASSERT(field);
+ thd->lex->current_select->no_wrap_view_item= TRUE;
+ if (!field->fixed)
+ {
+ if (field->fix_fields(thd, field_ref))
+ {
+ thd->lex->current_select->no_wrap_view_item= save_wrapper;
+ DBUG_RETURN(0);
+ }
+ field= *field_ref;
+ }
+ thd->lex->current_select->no_wrap_view_item= save_wrapper;
+ if (thd->lex->current_select->no_wrap_view_item)
+ {
+ DBUG_RETURN(field);
+ }
+ Item *item= new Item_direct_view_ref(&view->view->select_lex.context,
+ field_ref, view->view_name.str,
+ name);
+ DBUG_RETURN(item);
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
-#ifdef __GNUC__
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List<String>;
template class List_iterator<String>;
#endif
diff --git a/sql/table.h b/sql/table.h
index 8bc4e01852f..e5653a1f213 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -163,6 +163,13 @@ typedef struct st_table_share
my_bool crashed;
my_bool is_view;
my_bool name_lock, replace_with_name_lock;
+ /*
+ TRUE if this is a system table like 'mysql.proc', which we want to be
+ able to open and lock even when we already have some tables open and
+ locked. To avoid deadlocks we have to put certain restrictions on
+ locking of this table for writing. FALSE - otherwise.
+ */
+ my_bool system_table;
} TABLE_SHARE;
@@ -314,9 +321,9 @@ typedef struct st_schema_table
#define JOIN_TYPE_LEFT 1
#define JOIN_TYPE_RIGHT 2
-#define VIEW_ALGORITHM_UNDEFINED 0
-#define VIEW_ALGORITHM_TMPTABLE 1
-#define VIEW_ALGORITHM_MERGE 2
+#define VIEW_ALGORITHM_UNDEFINED 0
+#define VIEW_ALGORITHM_TMPTABLE 1
+#define VIEW_ALGORITHM_MERGE 2
/* view WITH CHECK OPTION parameter options */
#define VIEW_CHECK_NONE 0
@@ -329,9 +336,13 @@ typedef struct st_schema_table
#define VIEW_CHECK_SKIP 2
struct st_lex;
+struct st_table_list;
class select_union;
class TMP_TABLE_PARAM;
+Item *create_view_field(THD *thd, st_table_list *view, Item **field_ref,
+ const char *name);
+
struct Field_translator
{
Item *item;
@@ -384,6 +395,8 @@ typedef struct st_table_list
st_select_lex *select_lex;
st_lex *view; /* link on VIEW lex for merging */
Field_translator *field_translation; /* array of VIEW fields */
+ /* pointer to element after last one in translation table above */
+ Field_translator *field_translation_end;
/* list of ancestor(s) of this table (underlying table(s)/view(s) */
st_table_list *ancestor;
/* most upper view this table belongs to */
@@ -408,8 +421,7 @@ typedef struct st_table_list
algorithm)
*/
uint8 effective_with_check;
- uint effective_algorithm; /* which algorithm was really used */
- uint privilege_backup; /* place for saving privileges */
+ uint8 effective_algorithm; /* which algorithm was really used */
GRANT_INFO grant;
/* data need by some engines in query cache*/
ulonglong engine_data;
@@ -424,7 +436,6 @@ typedef struct st_table_list
bool updating; /* for replicate-do/ignore table */
bool force_index; /* prefer index over table scan */
bool ignore_leaves; /* preload only non-leaf nodes */
- bool no_where_clause; /* do not attach WHERE to SELECT */
table_map dep_tables; /* tables the table depends on */
table_map on_expr_dep_tables; /* tables on expression depends on */
struct st_nested_join *nested_join; /* if the element is a nested join */
@@ -437,6 +448,8 @@ typedef struct st_table_list
/* TRUE if this merged view contain auto_increment field */
bool contain_auto_increment;
bool multitable_view; /* TRUE iff this is multitable view */
+ /* view where processed */
+ bool where_processed;
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
@@ -449,16 +462,32 @@ typedef struct st_table_list
void calc_md5(char *buffer);
void set_ancestor();
int view_check_option(THD *thd, bool ignore_failure);
- bool setup_ancestor(THD *thd, Item **conds, uint8 check_option);
+ bool setup_ancestor(THD *thd);
void cleanup_items();
bool placeholder() {return derived || view; }
void print(THD *thd, String *str);
- void save_and_clear_want_privilege();
- void restore_want_privilege();
bool check_single_table(st_table_list **table, table_map map,
st_table_list *view);
bool set_insert_values(MEM_ROOT *mem_root);
+ void hide_view_error(THD *thd);
st_table_list *find_underlying_table(TABLE *table);
+ inline bool prepare_check_option(THD *thd)
+ {
+ bool res= FALSE;
+ if (effective_with_check)
+ res= prep_check_option(thd, effective_with_check);
+ return res;
+ }
+ inline bool prepare_where(THD *thd, Item **conds,
+ bool no_where_clause)
+ {
+ if (effective_algorithm == VIEW_ALGORITHM_MERGE)
+ return prep_where(thd, conds, no_where_clause);
+ return FALSE;
+ }
+private:
+ bool prep_check_option(THD *thd, uint8 check_opt_type);
+ bool prep_where(THD *thd, Item **conds, bool no_where_clause);
} TABLE_LIST;
class Item;
@@ -471,7 +500,7 @@ public:
virtual void next()= 0;
virtual bool end_of_fields()= 0; /* Return 1 at end of list */
virtual const char *name()= 0;
- virtual Item *item(THD *)= 0;
+ virtual Item *create_item(THD *)= 0;
virtual Field *field()= 0;
};
@@ -486,7 +515,7 @@ public:
void next() { ptr++; }
bool end_of_fields() { return *ptr == 0; }
const char *name();
- Item *item(THD *thd);
+ Item *create_item(THD *thd);
Field *field() { return *ptr; }
};
@@ -494,15 +523,18 @@ public:
class Field_iterator_view: public Field_iterator
{
Field_translator *ptr, *array_end;
+ TABLE_LIST *view;
public:
Field_iterator_view() :ptr(0), array_end(0) {}
void set(TABLE_LIST *table);
void next() { ptr++; }
bool end_of_fields() { return ptr == array_end; }
const char *name();
- Item *item(THD *thd) { return ptr->item; }
+ Item *create_item(THD *thd);
Item **item_ptr() {return &ptr->item; }
Field *field() { return 0; }
+
+ inline Item *item() { return ptr->item; }
};
diff --git a/sql/unireg.cc b/sql/unireg.cc
index e8aad2fedd0..7f170b3ef87 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -113,7 +113,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
}
reclength=uint2korr(forminfo+266);
- if ((file=create_frm(file_name, reclength, fileinfo,
+ if ((file=create_frm(thd, file_name, reclength, fileinfo,
create_info, keys)) < 0)
{
my_free((gptr) screen_buff,MYF(0));
diff --git a/strings/Makefile.am b/strings/Makefile.am
index a98908ad54a..5e02c7c1a2b 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -16,7 +16,7 @@
# This file is public domain and comes with NO WARRANTY of any kind
-INCLUDES = -I$(top_srcdir)/include
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
pkglib_LIBRARIES = libmystrings.a
# Exact one of ASSEMBLER_X
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 5844a6e688b..408e511d2e8 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -223,7 +223,7 @@ static int my_strnncoll_ucs2(CHARSET_INFO *cs,
t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc;
if ( s_wc != t_wc )
{
- return ((int) s_wc) - ((int) t_wc);
+ return s_wc > t_wc ? 1 : -1;
}
s+=s_res;
@@ -284,7 +284,7 @@ static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)),
int t_wc = uni_plane[t[0]] ? (int) uni_plane[t[0]][t[1]].sort :
(((int) t[0]) << 8) + (int) t[1];
if ( s_wc != t_wc )
- return s_wc - t_wc;
+ return s_wc > t_wc ? 1 : -1;
s+= 2;
t+= 2;
@@ -1364,7 +1364,7 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs,
}
if ( s_wc != t_wc )
{
- return ((int) s_wc) - ((int) t_wc);
+ return s_wc > t_wc ? 1 : -1;
}
s+=s_res;
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 53197972dab..de08c080b3b 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -2204,7 +2204,7 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs,
t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc;
if ( s_wc != t_wc )
{
- return ((int) s_wc) - ((int) t_wc);
+ return s_wc > t_wc ? 1 : -1;
}
s+=s_res;
@@ -2277,7 +2277,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs,
t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc;
if ( s_wc != t_wc )
{
- return ((int) s_wc) - ((int) t_wc);
+ return s_wc > t_wc ? 1 : -1;
}
s+=s_res;
@@ -2790,7 +2790,7 @@ static void test_mb(CHARSET_INFO *cs, uchar *s)
{
while(*s)
{
- if(my_ismbhead_utf8(cs,*s))
+ if (my_ismbhead_utf8(cs,*s))
{
int len=my_mbcharlen_utf8(cs,*s);
while(len--)
diff --git a/strings/ctype.c b/strings/ctype.c
index ba6dbaeb887..91fa1413259 100644
--- a/strings/ctype.c
+++ b/strings/ctype.c
@@ -218,14 +218,6 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len)
struct my_cs_file_section_st *s;
int state= (int)((s=cs_file_sec(st->attr, (int) strlen(st->attr))) ? s->state : 0);
-#ifndef DBUG_OFF
- if(0){
- char str[1024];
- mstr(str,attr,len,sizeof(str)-1);
- printf("VALUE %d %s='%s'\n",state,st->attr,str);
- }
-#endif
-
switch (state) {
case _CS_ID:
i->cs.number= strtol(attr,(char**)NULL,10);
diff --git a/strings/decimal.c b/strings/decimal.c
index 18f920badd3..1d75502f0da 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -739,11 +739,20 @@ int decimal_shift(decimal_t *dec, int shift)
beg= ROUND_UP(beg + 1) - 1;
end= ROUND_UP(end) - 1;
DBUG_ASSERT(new_point >= 0);
- new_point= ROUND_UP(new_point) - 1;
- for(; new_point > end; new_point--)
- dec->buf[new_point]= 0;
- for(; new_point < beg; new_point++)
- dec->buf[new_point]= 0;
+
+ /* We don't want negative new_point below */
+ if (new_point != 0)
+ new_point= ROUND_UP(new_point) - 1;
+
+ if (new_point > end)
+ do
+ {
+ dec->buf[new_point]=0;
+ }while (--new_point > end);
+ else
+ for (; new_point < beg; new_point++)
+ dec->buf[new_point]= 0;
+
dec->intg= digits_int;
dec->frac= digits_frac;
return err;
@@ -1434,6 +1443,7 @@ decimal_round(decimal_t *from, decimal_t *to, int scale,
intg1=ROUND_UP(from->intg +
(((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX)));
dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0;
+ int first_dig;
sanity(to);
@@ -1492,17 +1502,18 @@ decimal_round(decimal_t *from, decimal_t *to, int scale,
{
int do_inc= FALSE;
DBUG_ASSERT(frac0+intg0 >= 0);
- switch (round_digit)
- {
+ switch (round_digit) {
case 0:
{
dec1 *p0= buf0 + (frac1-frac0);
for (; p0 > buf0; p0--)
+ {
if (*p0)
{
do_inc= TRUE;
break;
- };
+ }
+ }
break;
}
case 5:
@@ -1511,9 +1522,10 @@ decimal_round(decimal_t *from, decimal_t *to, int scale,
do_inc= (x>5) || ((x == 5) &&
(mode == HALF_UP || (frac0+intg0 > 0 && *buf0 & 1)));
break;
- };
- default:;
- };
+ }
+ default:
+ break;
+ }
if (do_inc)
{
if (frac0+intg0>0)
@@ -1567,14 +1579,6 @@ decimal_round(decimal_t *from, decimal_t *to, int scale,
*buf1=1;
to->intg++;
}
- /* Here we check 999.9 -> 1000 case when we need to increase intg */
- else
- {
- int first_dig= to->intg % DIG_PER_DEC1;
- /* first_dig==0 should be handled above in the 'if' */
- if (first_dig && (*buf1 >= powers10[first_dig]))
- to->intg++;
- }
}
else
{
@@ -1595,6 +1599,12 @@ decimal_round(decimal_t *from, decimal_t *to, int scale,
}
}
}
+
+ /* Here we check 999.9 -> 1000 case when we need to increase intg */
+ first_dig= to->intg % DIG_PER_DEC1;
+ if (first_dig && (*buf1 >= powers10[first_dig]))
+ to->intg++;
+
if (scale<0)
scale=0;
diff --git a/strings/xml.c b/strings/xml.c
index 17f1b400957..02ca3932c39 100644
--- a/strings/xml.c
+++ b/strings/xml.c
@@ -96,13 +96,13 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a)
a->end=p->cur;
lex=a->beg[0];
}
- else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') )
+ else if ( (p->cur[0] == '"') || (p->cur[0] == '\'') )
{
p->cur++;
for( ; ( p->cur < p->end ) && (p->cur[0] != a->beg[0]); p->cur++)
{}
a->end=p->cur;
- if (a->beg[0]==p->cur[0])p->cur++;
+ if (a->beg[0] == p->cur[0])p->cur++;
a->beg++;
my_xml_norm_text(a);
lex=MY_XML_STRING;
@@ -169,8 +169,8 @@ static int my_xml_leave(MY_XML_PARSER *p, const char *str, uint slen)
int rc;
/* Find previous '.' or beginning */
- for( e=p->attrend; (e>p->attr) && (e[0]!='.') ; e--);
- glen = (uint) ((e[0]=='.') ? (p->attrend-e-1) : p->attrend-e);
+ for( e=p->attrend; (e>p->attr) && (e[0] != '.') ; e--);
+ glen = (uint) ((e[0] == '.') ? (p->attrend-e-1) : p->attrend-e);
if (str && (slen != glen))
{
@@ -199,7 +199,7 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len)
while ( p->cur < p->end )
{
MY_XML_ATTR a;
- if(p->cur[0]=='<')
+ if (p->cur[0] == '<')
{
int lex;
int question=0;
@@ -207,40 +207,40 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len)
lex=my_xml_scan(p,&a);
- if (MY_XML_COMMENT==lex)
+ if (MY_XML_COMMENT == lex)
{
continue;
}
lex=my_xml_scan(p,&a);
- if (MY_XML_SLASH==lex)
+ if (MY_XML_SLASH == lex)
{
- if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a)))
+ if (MY_XML_IDENT != (lex=my_xml_scan(p,&a)))
{
sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex));
return MY_XML_ERROR;
}
- if(MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))
+ if (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))
return MY_XML_ERROR;
lex=my_xml_scan(p,&a);
goto gt;
}
- if (MY_XML_EXCLAM==lex)
+ if (MY_XML_EXCLAM == lex)
{
lex=my_xml_scan(p,&a);
exclam=1;
}
- else if (MY_XML_QUESTION==lex)
+ else if (MY_XML_QUESTION == lex)
{
lex=my_xml_scan(p,&a);
question=1;
}
- if (MY_XML_IDENT==lex)
+ if (MY_XML_IDENT == lex)
{
- if(MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg)))
+ if (MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg)))
return MY_XML_ERROR;
}
else
@@ -250,17 +250,18 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len)
return MY_XML_ERROR;
}
- while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex))
+ while ((MY_XML_IDENT == (lex=my_xml_scan(p,&a))) ||
+ (MY_XML_STRING == lex))
{
MY_XML_ATTR b;
- if(MY_XML_EQ==(lex=my_xml_scan(p,&b)))
+ if (MY_XML_EQ == (lex=my_xml_scan(p,&b)))
{
lex=my_xml_scan(p,&b);
- if ( (lex==MY_XML_IDENT) || (lex==MY_XML_STRING) )
+ if ( (lex == MY_XML_IDENT) || (lex == MY_XML_STRING) )
{
- if((MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) ||
- (MY_XML_OK!=my_xml_value(p,b.beg,(uint) (b.end-b.beg))) ||
- (MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg))))
+ if ((MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) ||
+ (MY_XML_OK != my_xml_value(p,b.beg,(uint) (b.end-b.beg))) ||
+ (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg))))
return MY_XML_ERROR;
}
else
@@ -270,19 +271,19 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len)
return MY_XML_ERROR;
}
}
- else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) )
+ else if ((MY_XML_STRING == lex) || (MY_XML_IDENT == lex))
{
- if((MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) ||
- (MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg))))
+ if ((MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) ||
+ (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg))))
return MY_XML_ERROR;
}
else
break;
}
- if (lex==MY_XML_SLASH)
+ if (lex == MY_XML_SLASH)
{
- if(MY_XML_OK!=my_xml_leave(p,NULL,0))
+ if (MY_XML_OK != my_xml_leave(p,NULL,0))
return MY_XML_ERROR;
lex=my_xml_scan(p,&a);
}
@@ -290,23 +291,23 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len)
gt:
if (question)
{
- if (lex!=MY_XML_QUESTION)
+ if (lex != MY_XML_QUESTION)
{
sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex));
return MY_XML_ERROR;
}
- if(MY_XML_OK!=my_xml_leave(p,NULL,0))
+ if (MY_XML_OK != my_xml_leave(p,NULL,0))
return MY_XML_ERROR;
lex=my_xml_scan(p,&a);
}
if (exclam)
{
- if(MY_XML_OK!=my_xml_leave(p,NULL,0))
+ if (MY_XML_OK != my_xml_leave(p,NULL,0))
return MY_XML_ERROR;
}
- if (lex!=MY_XML_GT)
+ if (lex != MY_XML_GT)
{
sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex));
return MY_XML_ERROR;
@@ -315,11 +316,11 @@ gt:
else
{
a.beg=p->cur;
- for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++);
+ for ( ; (p->cur < p->end) && (p->cur[0] != '<') ; p->cur++);
a.end=p->cur;
my_xml_norm_text(&a);
- if (a.beg!=a.end)
+ if (a.beg != a.end)
{
my_xml_value(p,a.beg,(uint) (a.end-a.beg));
}
@@ -381,7 +382,7 @@ uint my_xml_error_pos(MY_XML_PARSER *p)
const char *s;
for ( s=p->beg ; s<p->cur; s++)
{
- if (s[0]=='\n')
+ if (s[0] == '\n')
beg=s;
}
return (uint) (p->cur-beg);
@@ -391,9 +392,9 @@ uint my_xml_error_lineno(MY_XML_PARSER *p)
{
uint res=0;
const char *s;
- for ( s=p->beg ; s<p->cur; s++)
+ for (s=p->beg ; s<p->cur; s++)
{
- if (s[0]=='\n')
+ if (s[0] == '\n')
res++;
}
return res;
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index b1ff78bdaf6..213530a2581 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -179,7 +179,7 @@ Summary: MySQL - server with extended functionality
Group: Applications/Databases
Provides: mysql-Max
Obsoletes: mysql-Max
-Requires: MySQL-server >= 4.0
+Requires: MySQL-server >= @MYSQL_BASE_VERSION@
%description Max
Optional MySQL server binary that supports additional features like:
@@ -440,19 +440,20 @@ then
/sbin/chkconfig --add mysql
fi
-# Create a MySQL user. Do not report any problems if it already
-# exists. This is redhat specific and should be handled more portable
-useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" %{mysqld_user} 2> /dev/null || true
+# Create a MySQL user and group. Do not report any problems if it already
+# exists.
+groupadd -r -c "MySQL server" %{mysqld_user} 2> /dev/null || true
+useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" -g %{mysqld_user} %{mysqld_user} 2> /dev/null || true
# Change permissions so that the user that will run the MySQL daemon
# owns all database files.
-chown -R %{mysqld_user} $mysql_datadir
+chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir
# Initiate databases
%{_bindir}/mysql_install_db --rpm --user=%{mysqld_user}
# Change permissions again to fix any new files.
-chown -R %{mysqld_user} $mysql_datadir
+chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir
# Fix permissions for the permission database so that only the user
# can read them.
@@ -667,6 +668,11 @@ fi
# itself - note that they must be ordered by date (important when
# merging BK trees)
%changelog
+* Fri Jul 15 2005 Lenz Grimmer <lenz@mysql.com>
+
+- create a "mysql" user group and assign the mysql user account to that group
+ in the server postinstall section. (BUG 10984)
+
* Tue Jun 14 2005 Lenz Grimmer <lenz@mysql.com>
- Do not build statically on i386 by default, only when adding either "--with
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ee3e31aa040..ca7f04c91f9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -37,7 +37,8 @@ noinst_PROGRAMS = insert_test select_test thread_test
#
# C Test for 4.1 protocol
#
-INCLUDES = -I$(top_srcdir)/include $(openssl_includes)
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(openssl_includes)
LIBS = @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ \
$(top_builddir)/libmysql/libmysqlclient.la
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 7a683659df6..557794ab1f6 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -173,6 +173,14 @@ DIE_UNLESS(stmt == 0);\
#define mytest_r(x) if (x) {myerror(NULL);DIE_UNLESS(FALSE);}
+/* A workaround for Sun Forte 5.6 on Solaris x86 */
+
+static int cmp_double(double *a, double *b)
+{
+ return *a == *b;
+}
+
+
/* Print the error message */
static void print_error(const char *msg)
@@ -690,7 +698,7 @@ static void verify_prepare_field(MYSQL_RES *result,
fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)",
field->org_table, org_table);
fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db);
- fprintf(stdout, "\n length :`%ld`\t(expected: `%ld`)",
+ fprintf(stdout, "\n length :`%lu`\t(expected: `%lu`)",
field->length, length * cs->mbmaxlen);
fprintf(stdout, "\n maxlength:`%ld`", field->max_length);
fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr);
@@ -1645,7 +1653,7 @@ static void test_prepare()
DIE_UNLESS(real_data == o_real_data);
DIE_UNLESS(length[5] == 4);
- DIE_UNLESS(double_data == o_double_data);
+ DIE_UNLESS(cmp_double(&double_data, &o_double_data));
DIE_UNLESS(length[6] == 8);
DIE_UNLESS(strcmp(data, str_data) == 0);
@@ -9858,7 +9866,7 @@ static void test_bug3035()
uint32 uint32_val;
longlong int64_val;
ulonglong uint64_val;
- double double_val, udouble_val;
+ double double_val, udouble_val, double_tmp;
char longlong_as_string[22], ulonglong_as_string[22];
/* mins and maxes */
@@ -10005,7 +10013,8 @@ static void test_bug3035()
DIE_UNLESS(int64_val == int64_min);
DIE_UNLESS(uint64_val == uint64_min);
DIE_UNLESS(double_val == (longlong) uint64_min);
- DIE_UNLESS(udouble_val == ulonglong2double(uint64_val));
+ double_tmp= ulonglong2double(uint64_val);
+ DIE_UNLESS(cmp_double(&udouble_val, &double_tmp));
DIE_UNLESS(!strcmp(longlong_as_string, "0"));
DIE_UNLESS(!strcmp(ulonglong_as_string, "0"));
@@ -10029,7 +10038,8 @@ static void test_bug3035()
DIE_UNLESS(int64_val == int64_max);
DIE_UNLESS(uint64_val == uint64_max);
DIE_UNLESS(double_val == (longlong) uint64_val);
- DIE_UNLESS(udouble_val == ulonglong2double(uint64_val));
+ double_tmp= ulonglong2double(uint64_val);
+ DIE_UNLESS(cmp_double(&udouble_val, &double_tmp));
DIE_UNLESS(!strcmp(longlong_as_string, "-1"));
DIE_UNLESS(!strcmp(ulonglong_as_string, "18446744073709551615"));
@@ -12995,6 +13005,19 @@ static void test_bug9478()
rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc == MYSQL_NO_DATA);
+ {
+ char buff[8];
+ /* Fill in the fethc packet */
+ int4store(buff, stmt->stmt_id);
+ buff[4]= 1; /* prefetch rows */
+ rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH, buff,
+ sizeof(buff), 0,0,1) ||
+ (*mysql->methods->read_query_result)(mysql));
+ DIE_UNLESS(rc);
+ if (!opt_silent && i == 0)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+ }
+
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
@@ -13027,27 +13050,6 @@ static void test_bug9478()
check_execute(stmt, rc);
if (!opt_silent && i == 0)
printf("Fetched row: %s\n", a);
- /*
- Although protocol-wise an attempt to execute a statement which
- already has an open cursor associated with it will yield an error,
- the client library behavior tested here is consistent with
- the non-cursor execution scenario: mysql_stmt_execute will
- silently close the cursor if necessary.
- */
- {
- char buff[9];
- /* Fill in the execute packet */
- int4store(buff, stmt->stmt_id);
- buff[4]= 0; /* Flag */
- int4store(buff+5, 1); /* Return 1 row */
- rc= ((*mysql->methods->advanced_command)(mysql, COM_EXECUTE, buff,
- sizeof(buff), 0,0,1) ||
- (*mysql->methods->read_query_result)(mysql));
- DIE_UNLESS(rc);
- if (!opt_silent && i == 0)
- printf("Got error (as expected): %s\n", mysql_error(mysql));
- }
-
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
@@ -13151,13 +13153,14 @@ static void test_bug9643()
static void test_bug11111()
{
- MYSQL_STMT *stmt;
- MYSQL_BIND bind[2];
- char buf[2][20];
- long len[2];
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[2];
+ char buf[2][20];
+ ulong len[2];
int i;
int rc;
- const char * query = "SELECT DISTINCT f1,ff2 FROM v1";
+ const char *query= "SELECT DISTINCT f1,ff2 FROM v1";
+
myheader("test_bug11111");
rc= mysql_query(mysql, "drop table if exists t1, t2, v1");
@@ -13175,24 +13178,27 @@ static void test_bug11111()
rc= mysql_query(mysql, "insert into t2 values (1,1), (2,2), (3,3)");
myquery(rc);
- stmt = mysql_stmt_init(mysql);
+ stmt= mysql_stmt_init(mysql);
mysql_stmt_prepare(stmt, query, strlen(query));
mysql_stmt_execute(stmt);
- for (i=0; i < 2; i++) {
- memset(&bind[i], '\0', sizeof(MYSQL_BIND));
+ bzero(bind, sizeof(bind));
+ for (i=0; i < 2; i++)
+ {
bind[i].buffer_type= MYSQL_TYPE_STRING;
bind[i].buffer= (gptr *)&buf[i];
bind[i].buffer_length= 20;
bind[i].length= &len[i];
}
- if (mysql_stmt_bind_result(stmt, bind))
- printf("Error: %s\n", mysql_stmt_error(stmt));
+ rc= mysql_stmt_bind_result(stmt, bind);
+ check_execute(stmt, rc);
- mysql_stmt_fetch(stmt);
- printf("return: %s", buf[1]);
+ rc= mysql_stmt_fetch(stmt);
+ check_execute(stmt, rc);
+ if (!opt_silent)
+ printf("return: %s", buf[1]);
DIE_UNLESS(!strcmp(buf[1],"1"));
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "drop view v1");
@@ -13262,6 +13268,488 @@ static void test_bug10729()
myquery(rc);
}
+
+/*
+ Check that mysql_next_result works properly in case when one of
+ the statements used in a multi-statement query is erroneous
+*/
+
+static void test_bug9992()
+{
+ MYSQL *mysql1;
+ MYSQL_RES* res ;
+ int rc;
+
+ myheader("test_bug9992");
+
+ if (!opt_silent)
+ printf("Establishing a connection with option CLIENT_MULTI_STATEMENTS..\n");
+
+ mysql1= mysql_init(NULL);
+
+ if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password,
+ opt_db ? opt_db : "test", opt_port, opt_unix_socket,
+ CLIENT_MULTI_STATEMENTS))
+ {
+ fprintf(stderr, "Failed to connect to the database\n");
+ DIE_UNLESS(0);
+ }
+
+
+ /* Sic: SHOW DATABASE is incorrect syntax. */
+ rc= mysql_query(mysql1, "SHOW TABLES; SHOW DATABASE; SELECT 1;");
+
+ if (rc)
+ {
+ fprintf(stderr, "[%d] %s\n", mysql_errno(mysql1), mysql_error(mysql1));
+ DIE_UNLESS(0);
+ }
+
+ if (!opt_silent)
+ printf("Testing mysql_store_result/mysql_next_result..\n");
+
+ res= mysql_store_result(mysql1);
+ DIE_UNLESS(res);
+ mysql_free_result(res);
+ rc= mysql_next_result(mysql1);
+ DIE_UNLESS(rc == 1); /* Got errors, as expected */
+
+ if (!opt_silent)
+ fprintf(stdout, "Got error, as expected:\n [%d] %s\n",
+ mysql_errno(mysql1), mysql_error(mysql1));
+
+ mysql_close(mysql1);
+}
+
+/* Bug#10736: cursors and subqueries, memroot management */
+
+static void test_bug10736()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[1];
+ char a[21];
+ int rc;
+ const char *stmt_text;
+ int i= 0;
+ ulong type;
+
+ myheader("test_bug10736");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (id integer not null primary key,"
+ "name VARCHAR(20) NOT NULL)");
+ rc= mysql_query(mysql, "insert into t1 (id, name) values "
+ "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+
+ type= (ulong) CURSOR_TYPE_READ_ONLY;
+ rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+ check_execute(stmt, rc);
+ stmt_text= "select name from t1 where name=(select name from t1 where id=2)";
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type= MYSQL_TYPE_STRING;
+ bind[0].buffer= (void*) a;
+ bind[0].buffer_length= sizeof(a);
+ mysql_stmt_bind_result(stmt, bind);
+
+ for (i= 0; i < 3; i++)
+ {
+ int row_no= 0;
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ while ((rc= mysql_stmt_fetch(stmt)) == 0)
+ {
+ if (!opt_silent)
+ printf("%d: %s\n", row_no, a);
+ ++row_no;
+ }
+ DIE_UNLESS(rc == MYSQL_NO_DATA);
+ }
+ rc= mysql_stmt_close(stmt);
+ DIE_UNLESS(rc == 0);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+/* Bug#10794: cursors, packets out of order */
+
+static void test_bug10794()
+{
+ MYSQL_STMT *stmt, *stmt1;
+ MYSQL_BIND bind[2];
+ char a[21];
+ int id_val;
+ ulong a_len;
+ int rc;
+ const char *stmt_text;
+ int i= 0;
+ ulong type;
+
+ myheader("test_bug10794");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (id integer not null primary key,"
+ "name varchar(20) not null)");
+ stmt= mysql_stmt_init(mysql);
+ stmt_text= "insert into t1 (id, name) values (?, ?)";
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type= MYSQL_TYPE_LONG;
+ bind[0].buffer= (void*) &id_val;
+ bind[1].buffer_type= MYSQL_TYPE_STRING;
+ bind[1].buffer= (void*) a;
+ bind[1].length= &a_len;
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+ for (i= 0; i < 42; i++)
+ {
+ id_val= (i+1)*10;
+ sprintf(a, "a%d", i);
+ a_len= strlen(a); /* safety against broken sprintf */
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ }
+ stmt_text= "select name from t1";
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ type= (ulong) CURSOR_TYPE_READ_ONLY;
+ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+ stmt1= mysql_stmt_init(mysql);
+ mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type= MYSQL_TYPE_STRING;
+ bind[0].buffer= (void*) a;
+ bind[0].buffer_length= sizeof(a);
+ bind[0].length= &a_len;
+ rc= mysql_stmt_bind_result(stmt, bind);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_fetch(stmt);
+ check_execute(stmt, rc);
+ if (!opt_silent)
+ printf("Fetched row from stmt: %s\n", a);
+ /* Don't optimize: an attribute of the original test case */
+ mysql_stmt_free_result(stmt);
+ mysql_stmt_reset(stmt);
+ stmt_text= "select name from t1 where id=10";
+ rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+ check_execute(stmt1, rc);
+ rc= mysql_stmt_bind_result(stmt1, bind);
+ check_execute(stmt1, rc);
+ rc= mysql_stmt_execute(stmt1);
+ while (1)
+ {
+ rc= mysql_stmt_fetch(stmt1);
+ if (rc == MYSQL_NO_DATA)
+ {
+ if (!opt_silent)
+ printf("End of data in stmt1\n");
+ break;
+ }
+ check_execute(stmt1, rc);
+ if (!opt_silent)
+ printf("Fetched row from stmt1: %s\n", a);
+ }
+ mysql_stmt_close(stmt);
+ mysql_stmt_close(stmt1);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
+/* Bug#11172: cursors, crash on a fetch from a datetime column */
+
+static void test_bug11172()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind_in[1], bind_out[2];
+ MYSQL_TIME hired;
+ int rc;
+ const char *stmt_text;
+ int i= 0, id;
+ ulong type;
+
+ myheader("test_bug11172");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (id integer not null primary key,"
+ "hired date not null)");
+ rc= mysql_query(mysql,
+ "insert into t1 (id, hired) values (1, '1933-08-24'), "
+ "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), "
+ "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')");
+ myquery(rc);
+ stmt= mysql_stmt_init(mysql);
+ stmt_text= "SELECT id, hired FROM t1 WHERE hired=?";
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+
+ type= (ulong) CURSOR_TYPE_READ_ONLY;
+ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+
+ bzero(bind_in, sizeof(bind_in));
+ bzero(bind_out, sizeof(bind_out));
+ bzero(&hired, sizeof(hired));
+ hired.year= 1965;
+ hired.month= 1;
+ hired.day= 1;
+ bind_in[0].buffer_type= MYSQL_TYPE_DATE;
+ bind_in[0].buffer= (void*) &hired;
+ bind_in[0].buffer_length= sizeof(hired);
+ bind_out[0].buffer_type= MYSQL_TYPE_LONG;
+ bind_out[0].buffer= (void*) &id;
+ bind_out[1]= bind_in[0];
+
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_stmt_bind_param(stmt, bind_in);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_bind_result(stmt, bind_out);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ while ((rc= mysql_stmt_fetch(stmt)) == 0)
+ {
+ if (!opt_silent)
+ printf("fetched data %d:%d-%d-%d\n", id,
+ hired.year, hired.month, hired.day);
+ }
+ DIE_UNLESS(rc == MYSQL_NO_DATA);
+ mysql_stmt_free_result(stmt) || mysql_stmt_reset(stmt);
+ }
+ mysql_stmt_close(stmt);
+ mysql_rollback(mysql);
+ mysql_rollback(mysql);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
+/* Bug#11656: cursors, crash on a fetch from a query with distinct. */
+
+static void test_bug11656()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[2];
+ int rc;
+ const char *stmt_text;
+ char buf[2][20];
+ int i= 0;
+ ulong type;
+
+ myheader("test_bug11656");
+
+ mysql_query(mysql, "drop table if exists t1");
+
+ rc= mysql_query(mysql, "create table t1 ("
+ "server varchar(40) not null, "
+ "test_kind varchar(1) not null, "
+ "test_id varchar(30) not null , "
+ "primary key (server,test_kind,test_id))");
+ myquery(rc);
+
+ stmt_text= "select distinct test_kind, test_id from t1 "
+ "where server in (?, ?)";
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ type= (ulong) CURSOR_TYPE_READ_ONLY;
+ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+
+ bzero(bind, sizeof(bind));
+ strcpy(buf[0], "pcint502_MY2");
+ strcpy(buf[1], "*");
+ for (i=0; i < 2; i++)
+ {
+ bind[i].buffer_type= MYSQL_TYPE_STRING;
+ bind[i].buffer= (gptr *)&buf[i];
+ bind[i].buffer_length= strlen(buf[i]);
+ }
+ mysql_stmt_bind_param(stmt, bind);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
+/*
+ Check that the server signals when NO_BACKSLASH_ESCAPES mode is in effect,
+ and mysql_real_escape_string() does the right thing as a result.
+*/
+
+static void test_bug10214()
+{
+ int len;
+ char out[8];
+
+ myheader("test_bug10214");
+
+ DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES));
+
+ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+ DIE_UNLESS(memcmp(out, "a\\'b\\\\c", len) == 0);
+
+ mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
+ DIE_UNLESS(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES);
+
+ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+ DIE_UNLESS(memcmp(out, "a''b\\c", len) == 0);
+
+ mysql_query(mysql, "set sql_mode=''");
+}
+
+static void test_client_character_set()
+{
+ MY_CHARSET_INFO cs;
+ char *csname= (char*) "utf8";
+ char *csdefault= (char*)mysql_character_set_name(mysql);
+ int rc;
+
+ myheader("test_client_character_set");
+
+ rc= mysql_set_character_set(mysql, csname);
+ DIE_UNLESS(rc == 0);
+
+ mysql_get_character_set_info(mysql, &cs);
+ DIE_UNLESS(!strcmp(cs.csname, "utf8"));
+ DIE_UNLESS(!strcmp(cs.name, "utf8_general_ci"));
+ /* Restore the default character set */
+ rc= mysql_set_character_set(mysql, csdefault);
+ myquery(rc);
+}
+
+/* Test correct max length for MEDIUMTEXT and LONGTEXT columns */
+
+static void test_bug9735()
+{
+ MYSQL_RES *res;
+ int rc;
+
+ myheader("test_bug9735");
+
+ rc= mysql_query(mysql, "drop table if exists t1");
+ myquery(rc);
+ rc= mysql_query(mysql, "create table t1 (a mediumtext, b longtext) "
+ "character set latin1");
+ myquery(rc);
+ rc= mysql_query(mysql, "select * from t1");
+ myquery(rc);
+ res= mysql_store_result(mysql);
+ verify_prepare_field(res, 0, "a", "a", MYSQL_TYPE_BLOB,
+ "t1", "t1", current_db, (1U << 24)-1, 0);
+ verify_prepare_field(res, 1, "b", "b", MYSQL_TYPE_BLOB,
+ "t1", "t1", current_db, ~0U, 0);
+ mysql_free_result(res);
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
+/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */
+
+static void test_bug11183()
+{
+ int rc;
+ MYSQL_STMT *stmt;
+ char bug_statement[]= "insert into t1 values (1)";
+
+ myheader("test_bug11183");
+
+ mysql_query(mysql, "drop table t1 if exists");
+ mysql_query(mysql, "create table t1 (a int)");
+
+ stmt= mysql_stmt_init(mysql);
+ DIE_UNLESS(stmt != 0);
+
+ rc= mysql_stmt_prepare(stmt, bug_statement, strlen(bug_statement));
+ check_execute(stmt, rc);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+
+ /* Trying to execute statement that should fail on execute stage */
+ rc= mysql_stmt_execute(stmt);
+ DIE_UNLESS(rc);
+
+ mysql_stmt_reset(stmt);
+ DIE_UNLESS(mysql_stmt_errno(stmt) == 0);
+
+ mysql_query(mysql, "create table t1 (a int)");
+
+ /* Trying to execute statement that should pass ok */
+ if (mysql_stmt_execute(stmt))
+ {
+ mysql_stmt_reset(stmt);
+ DIE_UNLESS(mysql_stmt_errno(stmt) == 0);
+ }
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+static void test_bug11037()
+{
+ MYSQL_STMT *stmt;
+ int rc;
+ const char *stmt_text;
+
+ myheader("test_bug11037");
+
+ mysql_query(mysql, "drop table if exists t1");
+
+ rc= mysql_query(mysql, "create table t1 (id int not null)");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "insert into t1 values (1)");
+ myquery(rc);
+
+ stmt_text= "select id FROM t1";
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+
+ /* expected error */
+ rc = mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc==1);
+ if (!opt_silent)
+ fprintf(stdout, "Got error, as expected:\n [%d] %s\n",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc==0);
+
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc==MYSQL_NO_DATA);
+
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc==MYSQL_NO_DATA);
+
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -13485,6 +13973,7 @@ static struct my_tests_st my_tests[]= {
{ "test_cursors_with_union", test_cursors_with_union },
{ "test_truncation", test_truncation },
{ "test_truncation_option", test_truncation_option },
+ { "test_client_character_set", test_client_character_set },
{ "test_bug8330", test_bug8330 },
{ "test_bug7990", test_bug7990 },
{ "test_bug8378", test_bug8378 },
@@ -13496,6 +13985,15 @@ static struct my_tests_st my_tests[]= {
{ "test_bug9643", test_bug9643 },
{ "test_bug10729", test_bug10729 },
{ "test_bug11111", test_bug11111 },
+ { "test_bug9992", test_bug9992 },
+ { "test_bug10736", test_bug10736 },
+ { "test_bug10794", test_bug10794 },
+ { "test_bug11172", test_bug11172 },
+ { "test_bug11656", test_bug11656 },
+ { "test_bug10214", test_bug10214 },
+ { "test_bug9735", test_bug9735 },
+ { "test_bug11183", test_bug11183 },
+ { "test_bug11037", test_bug11037 },
{ 0, 0 }
};
@@ -13600,23 +14098,6 @@ static void print_test_output()
}
}
-
-static void check_mupltiquery_bug9992()
-{
-
- MYSQL_RES* res ;
- mysql_query(mysql,"SHOW TABLES;SHOW DATABASE;SELECT 1;");
-
- fprintf(stdout, "\n\n!!! check_mupltiquery_bug9992 !!!\n");
- do
- {
- if (!(res= mysql_store_result(mysql)))
- return;
- mysql_free_result(res);
- } while (!mysql_next_result(mysql));
- fprintf(stdout, "\n\n!!! SUCCESS !!!\n");
- return;
-}
/***************************************************************************
main routine
***************************************************************************/
@@ -13682,10 +14163,7 @@ int main(int argc, char **argv)
}
client_disconnect(); /* disconnect from server */
-
- client_connect(CLIENT_MULTI_STATEMENTS);
- check_mupltiquery_bug9992();
- client_disconnect();
+
free_defaults(defaults_argv);
print_test_output();
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 651ef2d22b3..0f726bd5fc3 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -20,11 +20,11 @@ if HAVE_YASSL
else
yassl_dummy_link_fix=
endif
-INCLUDES=-I$(top_srcdir)/include $(openssl_includes) \
- -I$(top_builddir)/include
-LDADD= @CLIENT_EXTRA_LDFLAGS@ \
- $(top_builddir)/libmysql_r/libmysqlclient_r.la \
- @openssl_libs@ @ZLIB_LIBS@
+INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(openssl_includes)
+LDADD= @CLIENT_EXTRA_LDFLAGS@ \
+ $(top_builddir)/libmysql_r/libmysqlclient_r.la \
+ @openssl_libs@ @ZLIB_LIBS@
bin_PROGRAMS= mysqltestmanager
mysqltestmanager_SOURCES= mysqlmanager.c $(yassl_dummy_link_fix)
mysqltestmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
diff --git a/vio/Makefile.am b/vio/Makefile.am
index cd4212089c4..0d4f052b30a 100644
--- a/vio/Makefile.am
+++ b/vio/Makefile.am
@@ -19,7 +19,8 @@ if HAVE_YASSL
else
yassl_dummy_link_fix=
endif
-INCLUDES= -I$(top_srcdir)/include $(openssl_includes)
+INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(openssl_includes)
LDADD= @CLIENT_EXTRA_LDFLAGS@ $(openssl_libs)
pkglib_LIBRARIES= libvio.a
noinst_PROGRAMS = test-ssl test-sslserver test-sslclient
diff --git a/vio/vio.c b/vio/vio.c
index 6227493b994..bcf0ac032c8 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -143,7 +143,7 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
sprintf(vio->desc,
(vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
vio->sd);
-#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2)
+#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
#if !defined(NO_FCNTL_NONBLOCK)
#if defined(__FreeBSD__)
fcntl(sd, F_SETFL, vio->fcntl_mode); /* Yahoo! FreeBSD patch */
@@ -158,7 +158,7 @@ Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
{
/* set to blocking mode by default */
ulong arg=0, r;
- r = ioctlsocket(sd,FIONBIO,(void*) &arg, sizeof(arg));
+ r = ioctlsocket(sd,FIONBIO,(void*) &arg);
vio->fcntl_mode &= ~O_NONBLOCK;
}
#endif
diff --git a/vio/viosocket.c b/vio/viosocket.c
index ee8e85880ba..3b4013f4089 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -128,7 +128,7 @@ int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode,
DBUG_PRINT("enter", ("set_blocking_mode: %d old_mode: %d",
(int) set_blocking_mode, (int) *old_mode));
-#if !defined(___WIN__) && !defined(__EMX__)
+#if !defined(__WIN__) && !defined(__EMX__)
#if !defined(NO_FCNTL_NONBLOCK)
if (vio->sd >= 0)
{
@@ -161,7 +161,7 @@ int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode,
vio->fcntl_mode |= O_NONBLOCK; /* set bit */
}
if (old_fcntl != vio->fcntl_mode)
- r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
+ r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg);
}
#ifndef __EMX__
else
@@ -425,6 +425,7 @@ int vio_close_pipe(Vio * vio)
void vio_ignore_timeout(Vio *vio __attribute__((unused)),
+ uint which __attribute__((unused)),
uint timeout __attribute__((unused)))
{
}
diff --git a/vio/viossl.c b/vio/viossl.c
index 9a5eb1eb8df..7528e9071cf 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -316,7 +316,7 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
vio_blocking(vio, net_blocking, &unused);
DBUG_RETURN(1);
}
-#ifndef DBUF_OFF
+#ifndef DBUG_OFF
DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'"
,SSL_get_cipher_name((SSL*) vio->ssl_arg)));
client_cert = SSL_get_peer_certificate ((SSL*) vio->ssl_arg);
diff --git a/zlib/inftrees.c b/zlib/inftrees.c
index 8a896b28793..509461d9273 100644
--- a/zlib/inftrees.c
+++ b/zlib/inftrees.c
@@ -134,7 +134,7 @@ unsigned short FAR *work;
left -= count[len];
if (left < 0) return -1; /* over-subscribed */
}
- if (left > 0 && (type == CODES || (codes - count[0] != 1)))
+ if (left > 0 && (type == CODES || max != 1))
return -1; /* incomplete set */
/* generate offsets into symbol table for each length for sorting */